Advertisement
devil2010

Untitled

Apr 1st, 2022
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.25 KB | None | 0 0
  1. //
  2. // CallManager.swift
  3. // CallKitExample
  4. //
  5. // Created by Thehe on 9/24/20.
  6. // Copyright © 2020 Vadax. All rights reserved.
  7. //
  8.  
  9. import Foundation
  10. import UIKit
  11. import CallKit
  12. import AVFoundation
  13. import WebRTC
  14.  
  15. private let sharedManager = CallManager.init()
  16.  
  17. protocol CallManagerDelegate : AnyObject {
  18.  
  19. func callDidAnswer()
  20. func callDidEnd()
  21. func callDidHold(isOnHold : Bool)
  22. func callDidFail()
  23. }
  24.  
  25. class CallManager: NSObject, CXProviderDelegate {
  26.  
  27. var provider : CXProvider?
  28. var callController : CXCallController?
  29. var currentCall : CallInfoModel?
  30. var callBackgroundHandlerIdentifier : UIBackgroundTaskIdentifier?
  31. weak var delegate : CallManagerDelegate?
  32.  
  33. override init() {
  34. super.init()
  35. providerAndControllerSetup()
  36. NotificationCenter.default.addObserver(self, selector: #selector(callStateChanged(_:)), name: NSNotification.Name.VSLCallStateChanged, object: nil)
  37. }
  38.  
  39. deinit {
  40. NotificationCenter.default.removeObserver(self, name: NSNotification.Name.VSLCallStateChanged, object: nil)
  41. }
  42.  
  43. class var sharedInstance : CallManager {
  44. return sharedManager
  45. }
  46.  
  47. //MARK: - Setup
  48. func providerAndControllerSetup() {
  49. // configuration.ringtoneSound = "Ringtone.caf"
  50. createProvider()
  51. }
  52.  
  53. func createProvider(){
  54. // print("call manager createProvider")
  55. let configuration = CXProviderConfiguration.init(localizedName: "Link call manager")
  56. configuration.iconTemplateImageData = UIImage(named: "logo_square")?.pngData()
  57. configuration.supportsVideo = true
  58. configuration.maximumCallsPerCallGroup = 1
  59. configuration.maximumCallGroups = 1
  60. switch UserDefaults.standard.string(forKey: INCOMING_SOUND){
  61. case SOUND_DEFAULT:
  62. configuration.ringtoneSound = "Ringtone.caf"
  63. break
  64. case SOUND_PIANO:
  65. configuration.ringtoneSound = "sound.mp3"
  66. break
  67. default:
  68. break
  69. }
  70.  
  71. configuration.supportedHandleTypes = [.emailAddress, .phoneNumber, .generic]
  72. provider = CXProvider.init(configuration: configuration)
  73. provider?.setDelegate(self, queue: nil)
  74.  
  75. callController = CXCallController.init()
  76. }
  77.  
  78. func reportIncomingCallFor(call: CallInfoModel) {
  79. if !isOnPhoneCalling(call: call) && !call.isSipCall(){
  80. configureAudioSessionToDefaultSpeaker()
  81. }
  82. let update = CXCallUpdate.init()
  83. update.hasVideo = (call.Video == 1)
  84. update.supportsDTMF = false
  85. update.supportsGrouping = false
  86. update.supportsUngrouping = false
  87. update.supportsHolding = false
  88. update.remoteHandle = CXHandle.init(type: .emailAddress, value: call.CallerDisplay ?? UNKNOWN)
  89. update.localizedCallerName = call.CallerDisplay
  90. weak var weakSelf = self
  91. provider!.reportNewIncomingCall(with: call.uuid, update: update, completion: { (error : Error?) in
  92. if error != nil {
  93. weakSelf?.delegate?.callDidFail()
  94. print("callDidFail :\(String(describing: error?.localizedDescription))")
  95. AppDelegate.shared.sendLog("callDidFail :\(String(describing: error?.localizedDescription))")
  96. }else {
  97. //discard call immediately to endsure call screen is not show
  98. if self.isOnPhoneCalling(call: call){
  99. AppDelegate.shared.sendLog("reject call \(call.toJSON()) because user in on calling")
  100. print("reject call \(call.uuid) because user in on calling")
  101. self.provider?.reportCall(with: call.uuid, endedAt: Date(), reason: .remoteEnded)
  102. // self.rejectCall(call)
  103. return
  104. }
  105. weakSelf?.currentCall = call
  106. print("add new call: \(call.uuid)")
  107. AppDelegate.shared.callAnswerTimer?.invalidate()
  108. AppDelegate.shared.callAnswerTimer = nil
  109. AppDelegate.shared.callAnswerTimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.hangUpOnCallTimeOut), userInfo: nil, repeats: false)
  110.  
  111. if let roomJanusInfo = self.currentCall?.roomJanusInfo{
  112. guard let mediaRoomId = roomJanusInfo.MediaRoomId else { return }
  113. guard let roomPWd = roomJanusInfo.MediaRoomPassword else { return }
  114. guard let roomUrl = roomJanusInfo.MediaServerAddress else { return }
  115. var randomCallUUID = ""
  116. if let pushkit = UserDefaults.standard.string(forKey: PUSHKIT_TOKEN){
  117. randomCallUUID = String(pushkit.prefix(20))
  118. }else{
  119. randomCallUUID = UUID.init().uuidString
  120. }
  121. let senderName = "\(AppUtils.currentUser().Id)_\(randomCallUUID)"
  122.  
  123. var stuns = [RTCIceServer]()
  124. if !roomJanusInfo.iceServers.isEmpty{
  125. let iceServers = roomJanusInfo.iceServers
  126. if iceServers.filter({ $0.urls!.contains("stun:") }).count > 0{
  127. let mapped = iceServers.filter{ $0.urls!.contains("stun:")}.map{ $0.urls!}
  128. mapped.forEach { (url) in
  129. stuns.append(RTCIceServer(urlStrings: [url]))
  130. }
  131. }
  132.  
  133. if iceServers.filter({ $0.urls!.contains("turn:") }).count > 0{
  134. let mapped = iceServers.filter{ $0.urls!.contains("turn:")}
  135. stuns.append(contentsOf: mapped.map{
  136. RTCIceServer(urlStrings:[$0.urls!],
  137. username:$0.username!,
  138. credential:$0.credential!)
  139. })
  140. }
  141. }
  142. if stuns.isEmpty{
  143. stuns.append(RTCIceServer(urlStrings: ["stun:stun.l.google.com:19302"]))
  144. }
  145.  
  146. let roomManager = JanusRoomManager.shared
  147. roomManager.enableDataChannel = true
  148. roomManager.initRoom(roomID: mediaRoomId.intValue, roomUrl: roomUrl, roomPwd: roomPWd, senderName: senderName, iceServers: stuns, enableVideo : self.currentCall?.Video == 1, enableAudio: true, isSendAudio: true)
  149. roomManager.enableDataChannel = true
  150. if self.currentCall?.Video != 1{
  151. roomManager.isSingleCallWithVoiceOnly = true
  152. }
  153. roomManager.preConnect = true
  154. AppDelegate.shared.sendLog("start Janus while get incoming call")
  155. roomManager.connect()
  156. }
  157.  
  158. }
  159. })
  160. }
  161.  
  162. @objc func hangUpOnCallTimeOut(){
  163. AppDelegate.shared.callAnswerTimer?.invalidate()
  164. AppDelegate.shared.callAnswerTimer = nil
  165. if let c = currentCall{
  166. if !c.isAccepted{
  167. print("reject this call due to timeout(30s)")
  168. self.provider?.reportCall(with: c.uuid, endedAt: Date(), reason: .failed)
  169. if !c.isSipCall(){
  170. AppDelegate.shared.sendLog("reject this call due to timeout(30s)")
  171. rejectCall(c, status: Int(AX_ROOM_CALLING_ANSWER_TimeOut)!)
  172. }else{
  173.  
  174. }
  175. }
  176. }
  177. }
  178.  
  179. func isOnPhoneCalling(call: CallInfoModel) -> Bool{
  180. if AppDelegate.shared.isCalling{
  181. AppDelegate.shared.sendLog("isOnPhoneCalling true -> AppDelegate.shared.isCalling")
  182. return true
  183. }
  184. //ignore show callkit when user is in calling
  185. if call.Calling == Int(AX_CALL_TYPE_START) {
  186. if PIPKit.isActive {
  187. AppDelegate.shared.sendLog("isOnPhoneCalling true -> PIPKit.isActive")
  188. return true
  189. }
  190. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? MainVC {
  191. AppDelegate.shared.sendLog("isOnPhoneCalling true -> topMostViewController() as? MainVC")
  192. return true
  193. }
  194. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? IPPhoneCallScreen {
  195. AppDelegate.shared.sendLog("isOnPhoneCalling true -> topMostViewController() as? IPPhoneCallScreen")
  196. return true
  197. }
  198. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? SingleCallVC {
  199. AppDelegate.shared.sendLog("isOnPhoneCalling true -> topMostViewController() as? SingleCallVC")
  200. return true
  201. }
  202. var isCallingGroup = false
  203. if let chatVC = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? ChatVC {
  204. if chatVC.children.contains(where: { $0 is MainVC}){
  205. isCallingGroup = true
  206. }
  207. }
  208. guard !isCallingGroup else {
  209. AppDelegate.shared.sendLog("isOnPhoneCalling true -> isCallingGroup")
  210. return true
  211. }
  212. }
  213.  
  214. return false
  215. }
  216.  
  217. func isOnSinglePhoneCalling(call: CallInfoModel) -> Bool{
  218. if AppDelegate.shared.isCalling{
  219. return true
  220. }
  221. //ignore show callkit when user is in calling
  222. if call.Calling == Int(AX_CALL_TYPE_START) {
  223. if PIPKit.isActive {
  224. return true
  225. }
  226. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? IPPhoneCallScreen {
  227. return true
  228. }
  229. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? SingleCallVC {
  230. return true
  231. }
  232. if let _ = AppDelegate.shared.window?.rootViewController?.topMostViewController() as? IPPhoneCallScreen {
  233. return true
  234. }
  235. }
  236.  
  237. return false
  238. }
  239.  
  240. func startCallWithPhoneNumber(call : CallInfoModel) {
  241. configureAudioSessionToDefaultSpeaker()
  242. currentCall = call
  243. if let unwrappedCurrentCall = currentCall {
  244. let handle = CXHandle.init(type: .generic, value: unwrappedCurrentCall.CallerDisplay ?? UNKNOWN)
  245. let startCallAction = CXStartCallAction.init(call: unwrappedCurrentCall.uuid, handle: handle)
  246. let transaction = CXTransaction.init()
  247. transaction.addAction(startCallAction)
  248. requestTransaction(transaction: transaction)
  249.  
  250. self.provider?.reportOutgoingCall(with: startCallAction.callUUID, startedConnectingAt: nil)
  251. }
  252. }
  253.  
  254. func endCall() {
  255. if let unwrappedCurrentCall = currentCall {
  256. print("Call manager end call: \(unwrappedCurrentCall.uuid)")
  257. let endCallAction = CXEndCallAction.init(call: unwrappedCurrentCall.uuid)
  258. let transaction = CXTransaction.init()
  259. transaction.addAction(endCallAction)
  260. requestTransaction(transaction: transaction)
  261. }
  262. }
  263.  
  264. func endCall(uuid : UUID){
  265. let endCallAction = CXEndCallAction.init(call: uuid)
  266. let transaction = CXTransaction.init()
  267. transaction.addAction(endCallAction)
  268. requestTransaction(transaction: transaction)
  269. }
  270.  
  271. func holdCall(hold : Bool) {
  272. if let unwrappedCurrentCall = currentCall {
  273. let holdCallAction = CXSetHeldCallAction.init(call: unwrappedCurrentCall.uuid, onHold: hold)
  274. let transaction = CXTransaction.init()
  275. transaction.addAction(holdCallAction)
  276. requestTransaction(transaction: transaction)
  277. }
  278. }
  279.  
  280. func requestTransaction(transaction : CXTransaction) {
  281. weak var weakSelf = self
  282. callController?.request(transaction, completion: { (error : Error?) in
  283. if error != nil {
  284. print("requestTransaction error \(String(describing: error?.localizedDescription))")
  285. weakSelf?.delegate?.callDidFail()
  286. // if let call = weakSelf?.currentCall{
  287. // print("trying to mark call ended")
  288. // self.provider?.reportCall(with: call.uuid, endedAt: Date(), reason: .remoteEnded)
  289. // }
  290. }
  291. print("requestTransaction end call success")
  292. })
  293. }
  294.  
  295.  
  296. //MARK : - CXProviderDelegate
  297.  
  298. func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
  299. print("call manager CXStartCallAction")
  300. if let currentCall = currentCall{
  301. if currentCall.isSipCall(){
  302. print("start handle sip outgoing call")
  303. //ipcall here
  304. let callManager = VialerSIPLib.sharedInstance().callManager
  305. if let call = VialerSIPLib.sharedInstance().callManager.call(with: action.callUUID){
  306. callManager.audioController.configureAudioSession()
  307. call.start { error in
  308. if let error = error{
  309. print("error start ip call: \(error)")
  310. action.fail()
  311. return
  312. }
  313. print("start call success")
  314. let notificationInfo = [VSLNotificationUserInfoCallKey : call]
  315. NotificationCenter.default.post(name: NSNotification.Name.CallKitProviderDelegateOutboundCallStarted, object: AppDelegate.shared.providerDelegate, userInfo: notificationInfo)
  316. }
  317. }
  318. action.fulfill()
  319. }else{
  320. print("start link outgoing call")
  321. action.fulfill()
  322. }
  323.  
  324. }else{
  325. action.fail()
  326. }
  327.  
  328.  
  329. }
  330.  
  331. func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
  332. AppDelegate.shared.callAnswerTimer?.invalidate()
  333. AppDelegate.shared.callAnswerTimer = nil
  334. //todo: answer network call
  335. delegate?.callDidAnswer()
  336. if currentCall?.Video == 1{
  337. if SPPermission.camera.isDenied || SPPermission.microphone.isDenied{
  338. rejectCall(currentCall)
  339. self.currentCall = nil
  340. action.fail()
  341. AppDelegate.shared.sendNotify(Language.get("Can not accept call"), Language.get("Please accept microphone and camera permission to fully use our call service"), [:])
  342. return
  343. }
  344. }else{
  345. if SPPermission.microphone.isDenied{
  346. rejectCall(currentCall)
  347. self.currentCall = nil
  348. action.fail()
  349. AppDelegate.shared.sendNotify(Language.get("Can not accept call"), Language.get("Please accept microphone and camera permission to fully use our call service"), [:])
  350. return
  351. }
  352. }
  353. currentCall?.isAccepted = true
  354.  
  355. if let sipAccount = currentCall?.sipAccount, !sipAccount.isEmpty{
  356. let sb = UIStoryboard(name: "other", bundle: nil)
  357. let vc = sb.instantiateViewController(withIdentifier: "IPPhoneCallScreen") as! IPPhoneCallScreen
  358. vc.modalPresentationStyle = .fullScreen
  359. vc.callObj = currentCall
  360. let appDelegate = AppDelegate.shared
  361. if let topVC = appDelegate.window?.rootViewController?.topMostViewController(){
  362. topVC.present(vc, animated: true, completion: nil)
  363. }else{
  364. appDelegate.window?.rootViewController?.present(vc, animated: true, completion: nil)
  365. }
  366. }else{
  367. let sb = UIStoryboard(name: "main", bundle: nil)
  368. let vc = sb.instantiateViewController(withIdentifier: "SingleCallVC") as! SingleCallVC
  369. vc.modalPresentationStyle = .fullScreen
  370. vc.callObj = currentCall
  371. vc.isIncoming = true
  372.  
  373. //when app opened from call, the keyboard height not working because window is nil + app is not running to calculate keyboardheight
  374. let height = UserDefaults.standard.integer(forKey: KEYBOARD_SIZE)
  375. if Keyboard.height() == 0{
  376. Keyboard.measuredSize = CGRect(0, 0 , Int(UIScreen.main.bounds.width), height)
  377. }
  378. PIPKit.show(with: vc)
  379. }
  380.  
  381.  
  382. action.fulfill()
  383. }
  384.  
  385. func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
  386. //todo: configure audio session
  387. //todo: answer network call
  388. //stop timer
  389. AppDelegate.shared.callAnswerTimer?.invalidate()
  390. AppDelegate.shared.callAnswerTimer = nil
  391. print("Call manager CXEndCallAction")
  392. guard let currentCall = currentCall else {
  393. action.fail()
  394. return
  395. }
  396.  
  397. if currentCall.isSipCall(){
  398. print("end sip outgoing call")
  399. guard let sipCallUUID = currentCall.sipUUID else {
  400. action.fail()
  401. return
  402. }
  403.  
  404. if let call = VialerSIPLib.sharedInstance().callManager.call(with: sipCallUUID){
  405. if call.callState == .incoming{
  406. do{
  407. try call.decline()
  408. action.fulfill()
  409. }catch{
  410. action.fail()
  411. print("decline sip incoming call error : \(error.localizedDescription)")
  412. }
  413. }else{
  414. do{
  415. try call.hangup()
  416. action.fulfill()
  417. }catch{
  418. action.fail()
  419. print("hangup sip incoming call error : \(error.localizedDescription)")
  420. }
  421. }
  422. }else{
  423. print("can not find sip incomming call with uuid: \(action.callUUID)")
  424. action.fail()
  425. }
  426.  
  427. self.currentCall = nil
  428. }else{
  429. print("end link incomming call")
  430. if !currentCall.isAccepted{
  431. rejectCall(currentCall)
  432. let roomManager = JanusRoomManager.shared
  433. roomManager.reset()
  434. roomManager.disconnect()
  435. }else{
  436. //NOTE: While calling we use signalr message to end call,fcm push notification is only to end displaying call
  437. //But in lock screen press button can trigger this method
  438. //end call while calling -> send did end to singlecallvc
  439. if PIPKit.isActive{
  440. if let _ = PIPKit.rootViewController as? SingleCallVC{
  441. delegate?.callDidEnd()
  442. }
  443. }
  444. }
  445. self.currentCall = nil
  446. action.fulfill()
  447. }
  448. }
  449.  
  450.  
  451.  
  452. func configureRtcAudioSession(){
  453. // RTCDispatcher.dispatchAsync(on: RTCDispatcherQueueType.typeAudioSession) {
  454. // let audioSession = RTCAudioSession.sharedInstance()
  455. // audioSession.lockForConfiguration()
  456. // let configuration = RTCAudioSessionConfiguration.webRTC()
  457. // configuration.categoryOptions = [.allowBluetoothA2DP,.duckOthers, .allowBluetooth]
  458. // try? audioSession.setConfiguration(configuration)
  459. // audioSession.unlockForConfiguration()
  460. // }
  461. }
  462.  
  463. func configureAudioSessionToDefaultSpeaker() {
  464. let session = AVAudioSession.sharedInstance()
  465. do{
  466. try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .mixWithOthers, .allowAirPlay, .allowBluetooth, .allowBluetoothA2DP])
  467. } catch {
  468. print("========== Error in setting category \(error.localizedDescription)")
  469. }
  470. do{
  471. // try session.setMode(.voiceChat)
  472. // check if currentRoute is set to a bluetooth audio device
  473. let btOutputTypes: [AVAudioSession.Port] = [.bluetoothHFP, .bluetoothA2DP, .bluetoothLE]
  474. let btOutputs = AVAudioSession.sharedInstance().currentRoute.outputs.filter { btOutputTypes.contains($0.portType) }
  475.  
  476. // if so, set preferred audio input to built-in mic
  477. if !btOutputs.isEmpty {
  478. let builtInMicInput = AVAudioSession.sharedInstance().availableInputs?.filter { $0.portType == .builtInMic }.first
  479. try AVAudioSession.sharedInstance().setPreferredInput(builtInMicInput)
  480. } else {
  481. // set default input
  482. try AVAudioSession.sharedInstance().setPreferredInput(nil)
  483. }
  484. }catch {
  485. print("======== Error setting mode \(error.localizedDescription)")
  486. }
  487. do {
  488. if #available(iOS 13.0, *) {
  489. try session.setAllowHapticsAndSystemSoundsDuringRecording(true)
  490. } else {
  491. }
  492. } catch {
  493. print("======== Error setting haptic \(error.localizedDescription)")
  494. }
  495.  
  496. do {
  497. try session.setPreferredSampleRate(44100.0)
  498. } catch {
  499. print("======== Error setting rate \(error.localizedDescription)")
  500. }
  501. do {
  502. try session.setPreferredIOBufferDuration(0.005)
  503. } catch {
  504. print("======== Error IOBufferDuration \(error.localizedDescription)")
  505. }
  506. do {
  507. try session.setActive(true)
  508. } catch {
  509. print("========== Error starting session \(error.localizedDescription)")
  510. }
  511. }
  512.  
  513. func markCallIsConnecting(){
  514. guard let currentCall = currentCall else { return }
  515. provider?.reportOutgoingCall(with: currentCall.uuid, startedConnectingAt: nil)
  516. }
  517.  
  518. func markCallIsConnected(){
  519. guard let currentCall = currentCall else { return }
  520. provider?.reportOutgoingCall(with: currentCall.uuid, connectedAt: nil)
  521. }
  522.  
  523.  
  524.  
  525.  
  526. func rejectCall(_ callObj : CallInfoModel?, status : Int = Int(AX_ROOM_CALLING_ANSWER_Decline)!){
  527. guard let callObj = callObj else { return }
  528. guard let serverId = callObj.RoomServerId else { return }
  529. guard let roomId = callObj.RoomId else { return }
  530. guard let callId = callObj.CallId else { return }
  531. let url = "\(AppUtils.baseUrl(serverId: serverId))\(UPDATE_P2p_CALL_STATUS)"
  532.  
  533. let params = ["SessionId" : UserDefaults.standard.string(forKey: PUSHKIT_TOKEN)?.prefix(20) ?? UNKNOWN,
  534. "RoomId" : roomId,
  535. "CallId" : callId,
  536. "Status" : status,
  537. "ClientType" : 4000] as [String : Any]
  538.  
  539. NWUtils.shared.postData(url: url, params: params) { (response) in
  540. print("reject call success \(response)")
  541. if self.currentCall?.CallerId == callObj.CallerId{
  542. self.currentCall = nil
  543. }
  544.  
  545. } fail: { (error) in
  546. print("reject call fail \(error as! String)")
  547. if self.currentCall?.CallerId == callObj.CallerId{
  548. self.currentCall = nil
  549. }
  550. }
  551. }
  552.  
  553. func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
  554. guard let currentCall = currentCall else {
  555. action.fail()
  556. return
  557. }
  558.  
  559. if currentCall.isSipCall(){
  560. let callManager = VialerSIPLib.sharedInstance().callManager
  561. if let call = VialerSIPLib.sharedInstance().callManager.call(with: action.callUUID){
  562. do{
  563. try call.toggleHold()
  564. call.onHold ? callManager.audioController.deactivateAudioSession() : callManager.audioController.activateAudioSession()
  565. action.fulfill()
  566. }catch{
  567. action.fail()
  568. print("sip call hold failed: \(error.localizedDescription)")
  569. }
  570. }else{
  571. action.fail()
  572. }
  573. }else{
  574. action.fulfill()
  575. endCall()
  576. }
  577.  
  578. }
  579.  
  580. func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
  581. guard let currentCall = currentCall, let sipCallUUID = currentCall.sipUUID else {
  582. action.fail()
  583. return
  584. }
  585.  
  586. if currentCall.isSipCall(){
  587. if let call = VialerSIPLib.sharedInstance().callManager.call(with: sipCallUUID){
  588. do{
  589. try call.toggleMute()
  590. action.fulfill()
  591. }catch{
  592. action.fail()
  593. print("sip call mute failed: \(error.localizedDescription)")
  594. }
  595. }else{
  596. action.fail()
  597. }
  598. }else{
  599. action.fulfill()
  600. endCall()
  601. }
  602. }
  603.  
  604. func provider(_ provider: CXProvider, perform action: CXSetGroupCallAction) {
  605. }
  606.  
  607. func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {
  608. guard let currentCall = currentCall, let sipCallUUID = currentCall.sipUUID else {
  609. action.fail()
  610. return
  611. }
  612.  
  613. if currentCall.isSipCall(){
  614. if let call = VialerSIPLib.sharedInstance().callManager.call(with: sipCallUUID){
  615. do{
  616. try call.sendDTMF(action.digits)
  617. action.fulfill()
  618. }catch{
  619. action.fail()
  620. print("sip call send dtmf failed: \(error.localizedDescription)")
  621. }
  622. }else{
  623. action.fail()
  624. }
  625. }else{
  626. action.fulfill()
  627. endCall()
  628. }
  629. }
  630.  
  631. // Called when an action was not performed in time and has been inherently failed. Depending on the action, this timeout may also force the call to end. An action that has already timed out should not be fulfilled or failed by the provider delegate
  632. func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
  633. // React to the action timeout if necessary, such as showing an error UI.
  634. }
  635.  
  636. /// Called when the provider's audio session activation state changes.
  637. func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
  638. print("callmanager audioSessionDidActivate")
  639. if let currentCall = currentCall, currentCall.isSipCall(){
  640. // VialerSIPLib.sharedInstance().callManager.audioController.activateAudioSession()
  641. }
  642. }
  643.  
  644. func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
  645. print("callmanager audioSessionDidDeactivate")
  646. if let currentCall = currentCall, currentCall.isSipCall(){
  647. // VialerSIPLib.sharedInstance().callManager.audioController.deactivateAudioSession()
  648. }
  649. }
  650.  
  651. func providerDidReset(_ provider: CXProvider) {
  652. print("providerDidReset")
  653. if let currentCall = currentCall, currentCall.isSipCall(){
  654. VialerSIPLib.sharedInstance().callManager.endAllCalls()
  655. }
  656. }
  657.  
  658. @objc func callStateChanged(_ notification: Notification){
  659. guard let call = notification.userInfo?[VSLNotificationUserInfoCallKey] as? VSLCall else { return }
  660. print("callStateChanged: \(call.callState.rawValue)")
  661. guard let currentCall = currentCall else { return }
  662. //report based on call UUID , not sip uuid
  663. if call.callState == .calling{
  664. if !call.isIncoming{
  665. provider?.reportOutgoingCall(with: currentCall.uuid, startedConnectingAt: Date())
  666. }
  667. }else if call.callState == .early{
  668. if !call.isIncoming{
  669. provider?.reportOutgoingCall(with: currentCall.uuid, startedConnectingAt: Date())
  670. }
  671. }else if call.callState == .connecting{
  672. if !call.isIncoming{
  673. provider?.reportOutgoingCall(with: currentCall.uuid, startedConnectingAt: Date())
  674. }
  675. }else if call.callState == .confirmed{
  676. if !call.isIncoming{
  677. provider?.reportOutgoingCall(with: currentCall.uuid, connectedAt: Date())
  678. }
  679. }else if call.callState == .disconnected{
  680. if !call.connected{
  681. provider?.reportOutgoingCall(with: currentCall.uuid, connectedAt: Date())
  682. provider?.reportCall(with: currentCall.uuid, endedAt: Date(), reason: .answeredElsewhere)
  683. }else if !call.userDidHangUp{
  684. provider?.reportCall(with: currentCall.uuid, endedAt: Date(), reason: .remoteEnded)
  685. }
  686. }
  687.  
  688. }
  689. }
  690.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement