diff --git a/Classes/Swift/CallManager.swift b/Classes/Swift/CallManager.swift index 429b678bf..07f38e44a 100644 --- a/Classes/Swift/CallManager.swift +++ b/Classes/Swift/CallManager.swift @@ -1,21 +1,21 @@ /* -* Copyright (c) 2010-2020 Belledonne Communications SARL. -* -* This file is part of linphone-iphone -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ import Foundation import linphonesw @@ -28,13 +28,13 @@ import AVFoundation @objc var batteryWarningShown = false @objc var videoRequested = false /*set when user has requested for video*/ @objc var isConference = false - + } /* -* CallManager is a class that manages application calls and supports callkit. -* There is only one CallManager by calling CallManager.instance(). -*/ + * CallManager is a class that manages application calls and supports callkit. + * There is only one CallManager by calling CallManager.instance(). + */ @objc class CallManager: NSObject, CoreDelegate { static var theCallManager: CallManager? let providerDelegate: ProviderDelegate! // to support callkit @@ -55,25 +55,25 @@ import AVFoundation var backgroundContextCall : Call? @objc var backgroundContextCameraIsEnabled : Bool = false - + fileprivate override init() { providerDelegate = ProviderDelegate.shared callController = CXCallController() } - + @objc static func instance() -> CallManager { if (theCallManager == nil) { theCallManager = CallManager() } return theCallManager! } - - + + @objc func setCore(core: OpaquePointer) { lc = Core.getSwiftObject(cObject: core) lc?.addDelegate(delegate: self) } - + @objc static func getAppData(call: OpaquePointer) -> CallAppData? { let sCall = Call.getSwiftObject(cObject: call) return getAppData(sCall: sCall) @@ -85,7 +85,7 @@ import AVFoundation } return Unmanaged.fromOpaque(sCall.userData!).takeUnretainedValue() } - + @objc static func setAppData(call:OpaquePointer, appData: CallAppData) { let sCall = Call.getSwiftObject(cObject: call) setAppData(sCall: sCall, appData: appData) @@ -101,12 +101,12 @@ import AVFoundation sCall.userData = UnsafeMutableRawPointer(Unmanaged.passRetained(appData!).toOpaque()) } } - + @objc func findCall(callId: String?) -> OpaquePointer? { let call = callByCallId(callId: callId) return call?.getCobject } - + func callByCallId(callId: String?) -> Call? { if (callId == nil) { return nil @@ -117,7 +117,7 @@ import AVFoundation } return nil } - + @objc func stopLinphoneCore() { if (lc?.callsNb == 0) { lc?.stopAsync() @@ -136,11 +136,11 @@ import AVFoundation } @objc static func callKitEnabled() -> Bool { - #if !targetEnvironment(simulator) +#if !targetEnvironment(simulator) if ConfigManager.instance().lpConfigBoolForKey(key: "use_callkit", section: "app") { return true } - #endif +#endif return false } @@ -211,17 +211,17 @@ import AVFoundation } } } - + func displayIncomingCall(call:Call?, handle: String, hasVideo: Bool, callId: String, displayName:String) { let uuid = UUID() let callInfo = CallInfo.newIncomingCallInfo(callId: callId) - + providerDelegate.callInfos.updateValue(callInfo, forKey: uuid) providerDelegate.uuids.updateValue(uuid, forKey: callId) providerDelegate.reportIncomingCall(call:call, uuid: uuid, handle: handle, hasVideo: hasVideo, displayName: displayName) } - + @objc func acceptCall(call: OpaquePointer?, hasVideo:Bool) { if (call == nil) { Log.directLog(BCTBX_LOG_ERROR, text: "Can not accept null call!") @@ -230,7 +230,7 @@ import AVFoundation let call = Call.getSwiftObject(cObject: call!) acceptCall(call: call, hasVideo: hasVideo) } - + func acceptCall(call: Call, hasVideo:Bool) { do { let callParams = try lc!.createCallParams(call: call) @@ -242,7 +242,7 @@ import AVFoundation } callParams.lowBandwidthEnabled = low_bandwidth } - + //We set the record file name here because we can't do it after the call is started. let address = call.callLog?.fromAddress let writablePath = AppManager.recordingFilePathFromCall(address: address?.username ?? "") @@ -268,14 +268,14 @@ import AVFoundation Log.directLog(BCTBX_LOG_ERROR, text: "accept call failed \(error)") } } - + // for outgoing call. There is not yet callId @objc func startCall(addr: OpaquePointer?, isSas: Bool, isVideo: Bool, isConference: Bool = false) { if (addr == nil) { print("Can not start a call with null address!") return } - + let sAddr = Address.getSwiftObject(cObject: addr!) if (CallManager.callKitEnabled() && !CallManager.instance().nextCallIsTransfer && lc?.conference?.isIn != true) { let uuid = UUID() @@ -283,11 +283,11 @@ import AVFoundation let handle = CXHandle(type: .generic, value: sAddr.asStringUriOnly()) let startCallAction = CXStartCallAction(call: uuid, handle: handle) let transaction = CXTransaction(action: startCallAction) - + let callInfo = CallInfo.newOutgoingCallInfo(addr: sAddr, isSas: isSas, displayName: name, isVideo: isVideo, isConference:isConference) providerDelegate.callInfos.updateValue(callInfo, forKey: uuid) providerDelegate.uuids.updateValue(uuid, forKey: "") - + setHeldOtherCalls(exceptCallid: "") requestTransaction(transaction, action: "startCall") }else { @@ -297,30 +297,30 @@ import AVFoundation func startCall(addr:String, isSas: Bool = false, isVideo: Bool, isConference: Bool = false) { do { - let address = try Factory.Instance.createAddress(addr: addr) + let address = try Factory.Instance.createAddress(addr: addr) startCall(addr: address.getCobject,isSas: isSas, isVideo: isVideo, isConference:isConference) } catch { Log.e("[CallManager] unable to create address for a new outgoing call : \(addr) \(error) ") } } - + func doCall(addr: Address, isSas: Bool, isVideo: Bool, isConference:Bool = false) throws { let displayName = FastAddressBook.displayName(for: addr.getCobject) - + let lcallParams = try CallManager.instance().lc!.createCallParams(call: nil) if ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference") && AppManager.network() == .network_2g { Log.directLog(BCTBX_LOG_MESSAGE, text: "Enabling low bandwidth mode") lcallParams.lowBandwidthEnabled = true } - + if (displayName != nil) { try addr.setDisplayname(newValue: displayName!) } - + if(ConfigManager.instance().lpConfigBoolForKey(key: "override_domain_with_default_one")) { try addr.setDomain(newValue: ConfigManager.instance().lpConfigStringForKey(key: "domain", section: "assistant")) } - + if (CallManager.instance().nextCallIsTransfer) { let call = CallManager.instance().lc!.currentCall try call?.transferTo(referTo: addr) @@ -362,7 +362,7 @@ import AVFoundation } } } - + @objc func groupCall() { if (CallManager.callKitEnabled()) { let calls = lc?.calls @@ -371,29 +371,29 @@ import AVFoundation } let firstCall = calls!.first?.callLog?.callId ?? "" let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : "" - + let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"] if (currentUuid == nil) { Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.") return } - + let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"] let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid) let transcation = CXTransaction(action: groupAction) requestTransaction(transcation, action: "groupCall") - + setResumeCalls() } else { try? lc?.addAllToConference() } } - + @objc func removeAllCallInfos() { providerDelegate.callInfos.removeAll() providerDelegate.uuids.removeAll() } - + @objc func terminateCall(call: OpaquePointer?) { if (call == nil) { Log.directLog(BCTBX_LOG_ERROR, text: "Can not terminate null call!") @@ -407,12 +407,12 @@ import AVFoundation Log.directLog(BCTBX_LOG_ERROR, text: "Failed to terminate call failed because \(error)") } } - + @objc func markCallAsDeclined(callId: String) { if !CallManager.callKitEnabled() { return } - + let uuid = providerDelegate.uuids["\(callId)"] if (uuid == nil) { Log.directLog(BCTBX_LOG_MESSAGE, text: "Mark call \(callId) as declined.") @@ -426,7 +426,7 @@ import AVFoundation providerDelegate.endCall(uuid: uuid!) } } - + @objc func setHeld(call: OpaquePointer, hold: Bool) { let sCall = Call.getSwiftObject(cObject: call) if (!hold) { @@ -437,13 +437,13 @@ import AVFoundation func setHeld(call: Call, hold: Bool) { - #if targetEnvironment(simulator) +#if targetEnvironment(simulator) if (hold) { try?call.pause() } else { try?call.resume() } - #else +#else let callid = call.callLog?.callId ?? "" let uuid = providerDelegate.uuids["\(callid)"] if (uuid == nil) { @@ -453,9 +453,9 @@ import AVFoundation let setHeldAction = CXSetHeldCallAction(call: uuid!, onHold: hold) let transaction = CXTransaction(action: setHeldAction) requestTransaction(transaction, action: "setHeld") - #endif +#endif } - + @objc func setHeldOtherCalls(exceptCallid: String) { for call in CallManager.instance().lc!.calls { if (call.callLog?.callId != exceptCallid && call.state != .Paused && call.state != .Pausing && call.state != .PausedByRemote) { @@ -463,7 +463,7 @@ import AVFoundation } } } - + func setResumeCalls() { for call in CallManager.instance().lc!.calls { if (call.state == .Paused || call.state == .Pausing || call.state == .PausedByRemote) { @@ -471,7 +471,7 @@ import AVFoundation } } } - + @objc func performActionWhenCoreIsOn(action: @escaping ()->Void ) { if (globalState == .On) { action() @@ -479,14 +479,14 @@ import AVFoundation actionsToPerformOnceWhenCoreIsOn.append(action) } } - + @objc func acceptVideo(call: OpaquePointer, confirm: Bool) { let sCall = Call.getSwiftObject(cObject: call) let params = try? lc?.createCallParams(call: sCall) params?.videoEnabled = confirm try? sCall.acceptUpdate(params: params) } - + func onGlobalStateChanged(core: Core, state: GlobalState, message: String) { if (state == .On) { actionsToPerformOnceWhenCoreIsOn.forEach { @@ -496,7 +496,7 @@ import AVFoundation } globalState = state } - + func onRegistrationStateChanged(core: Core, proxyConfig: ProxyConfig, state: RegistrationState, message: String) { if core.proxyConfigList.count == 1 && (state == .Failed || state == .Cleared){ // terminate callkit immediately when registration failed or cleared, supporting single proxy configuration @@ -509,7 +509,7 @@ import AVFoundation continue } } - + CallManager.instance().providerDelegate.endCall(uuid: call.value) } CallManager.instance().endCallkit = true @@ -536,7 +536,7 @@ import AVFoundation return FastAddressBook.displayName(for: call.remoteAddress?.getCobject) ?? "Unknown" } } - + func onCallStateChanged(core: Core, call: Call, state cstate: Call.State, message: String) { let callLog = call.callLog let callId = callLog?.callId @@ -544,7 +544,7 @@ import AVFoundation displayIncomingCall(call: call, handle: "Calling", hasVideo: false, callId: callId!, displayName: "Calling") } else { let video = (core.videoActivationPolicy?.automaticallyAccept ?? false) && (call.remoteParams?.videoEnabled ?? false) - + if (call.userData == nil) { let appData = CallAppData() CallManager.setAppData(sCall: call, appData: appData) @@ -555,11 +555,11 @@ import AVFoundation ConferenceViewModel.shared.initConference(conference) ConferenceViewModel.shared.configureConference(conference) } - + switch cstate { - case .IncomingReceived: - let addr = call.remoteAddress - var displayName = incomingDisplayName(call: call) + case .IncomingReceived: + let addr = call.remoteAddress + var displayName = incomingDisplayName(call: call) if call.replacedCall != nil { endCallKitReplacedCall = false @@ -572,174 +572,174 @@ import AVFoundation CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId) CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName) } else if (CallManager.callKitEnabled()) { - let isConference = isConferenceCall(call: call) - let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet. - if (isEarlyConference) { - CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in - let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] - if (uuid != nil) { - displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))" - CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName) - } + let isConference = isConferenceCall(call: call) + let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet. + if (isEarlyConference) { + CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in + let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] + if (uuid != nil) { + displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))" + CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName) } } + } + + let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] + if call.replacedCall == nil { + CallManager.uuidReplacedCall = callId + } + + if (uuid != nil) { + // Tha app is now registered, updated the call already existed. + CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName) + } else { + CallManager.instance().displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: video, callId: callId!, displayName: displayName) + } + } else if (UIApplication.shared.applicationState != .active) { + // not support callkit , use notif + let content = UNMutableNotificationContent() + content.title = NSLocalizedString("Incoming call", comment: "") + content.body = displayName + content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf")) + content.categoryIdentifier = "call_cat" + content.userInfo = ["CallId" : callId!] + let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil) + UNUserNotificationCenter.current().add(req, withCompletionHandler: nil) + } + break + case .StreamsRunning: + if (CallManager.callKitEnabled()) { + let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] + if (uuid != nil) { + let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] + if (callInfo != nil && callInfo!.isOutgoing && !callInfo!.connected) { + Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call connected with uuid \(uuid!) and callId \(callId!)") + CallManager.instance().providerDelegate.reportOutgoingCallConnected(uuid: uuid!) + callInfo!.connected = true + CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) + } + } + } + + if (CallManager.instance().speakerBeforePause) { + CallManager.instance().speakerBeforePause = false + CallManager.instance().changeRouteToSpeaker() + } + actionToFulFill?.fulfill() + actionToFulFill = nil + break + case .Paused: + actionToFulFill?.fulfill() + actionToFulFill = nil + break + case .OutgoingInit, + .OutgoingProgress, + .OutgoingRinging, + .OutgoingEarlyMedia: + if (CallManager.callKitEnabled()) { + let uuid = CallManager.instance().providerDelegate.uuids[""] + if (uuid != nil) { + let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] + callInfo!.callId = callId! + CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) + CallManager.instance().providerDelegate.uuids.removeValue(forKey: "") + CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callId!) + + Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)") + CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!) + } else { + if CallManager.instance().isConferenceCall(call: call) { + let uuid = UUID() + let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true) + CallManager.instance().providerDelegate.callInfos.updateValue(callInfo, forKey: uuid) + CallManager.instance().providerDelegate.uuids.updateValue(uuid, forKey: "") + CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid) + Core.get().activateAudioSession(actived: true) + } else { + CallManager.instance().referedToCall = callId + } + } + } + break + case .End, + .Error: + var displayName = "Unknown" + if (call.dir == .Incoming) { + displayName = incomingDisplayName(call: call) + } else if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) { + displayName = contactName + } + + UIDevice.current.isProximityMonitoringEnabled = false + if (CallManager.instance().lc!.callsNb == 0) { + CallManager.instance().changeRouteToDefault() + // disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE; + // furthermore it introduces a bug when calling multiple times since route may not be + // reconfigured between cause leading to bluetooth being disabled while it should not + //CallManager.instance().bluetoothEnabled = false + } + + if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) { + // Configure the notification's payload. + let content = UNMutableNotificationContent() + content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil) + content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil) + + // Deliver the notification. + let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification. + let center = UNUserNotificationCenter.current() + center.add(request) { (error : Error?) in + if error != nil { + Log.directLog(BCTBX_LOG_ERROR, text: "Error while adding notification request : \(error!.localizedDescription)") + } + } + } + + if (CallManager.callKitEnabled()) { + var uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] + if (callId == CallManager.instance().referedToCall) { + // refered call ended before connecting + Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered to call : \(String(describing: CallManager.instance().referedToCall))") + CallManager.instance().referedFromCall = nil + CallManager.instance().referedToCall = nil + } + if uuid == nil { + // the call not yet connected + uuid = CallManager.instance().providerDelegate.uuids[""] + } + if (uuid != nil) { + if (callId == CallManager.instance().referedFromCall) { + Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered from call : \(String(describing: CallManager.instance().referedFromCall))") + CallManager.instance().referedFromCall = nil + let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] + callInfo!.callId = CallManager.instance().referedToCall ?? "" + CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) + CallManager.instance().providerDelegate.uuids.removeValue(forKey: callId!) + CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId) + CallManager.instance().referedToCall = nil + break + } + if (endCallKitReplacedCall){ + let transaction = CXTransaction(action: + CXEndCallAction(call: uuid!)) + CallManager.instance().requestTransaction(transaction, action: "endCall") + }else{ + endCallKitReplacedCall = true + } - let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] - if call.replacedCall == nil { - CallManager.uuidReplacedCall = callId - } - - if (uuid != nil) { - // Tha app is now registered, updated the call already existed. - CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName) - } else { - CallManager.instance().displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: video, callId: callId!, displayName: displayName) - } - } else if (UIApplication.shared.applicationState != .active) { - // not support callkit , use notif - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Incoming call", comment: "") - content.body = displayName - content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf")) - content.categoryIdentifier = "call_cat" - content.userInfo = ["CallId" : callId!] - let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil) - UNUserNotificationCenter.current().add(req, withCompletionHandler: nil) } - break - case .StreamsRunning: - if (CallManager.callKitEnabled()) { - let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] - if (uuid != nil) { - let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] - if (callInfo != nil && callInfo!.isOutgoing && !callInfo!.connected) { - Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call connected with uuid \(uuid!) and callId \(callId!)") - CallManager.instance().providerDelegate.reportOutgoingCallConnected(uuid: uuid!) - callInfo!.connected = true - CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) - } - } - } - - if (CallManager.instance().speakerBeforePause) { - CallManager.instance().speakerBeforePause = false - CallManager.instance().changeRouteToSpeaker() - } - actionToFulFill?.fulfill() - actionToFulFill = nil - break - case .Paused: - actionToFulFill?.fulfill() - actionToFulFill = nil + } + break + case .Released: + CallManager.setAppData(sCall : call, appData : nil); + break + case .Referred: + CallManager.instance().referedFromCall = call.callLog?.callId + break + default: break - case .OutgoingInit, - .OutgoingProgress, - .OutgoingRinging, - .OutgoingEarlyMedia: - if (CallManager.callKitEnabled()) { - let uuid = CallManager.instance().providerDelegate.uuids[""] - if (uuid != nil) { - let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] - callInfo!.callId = callId! - CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) - CallManager.instance().providerDelegate.uuids.removeValue(forKey: "") - CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callId!) - - Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)") - CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!) - } else { - if CallManager.instance().isConferenceCall(call: call) { - let uuid = UUID() - let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true) - CallManager.instance().providerDelegate.callInfos.updateValue(callInfo, forKey: uuid) - CallManager.instance().providerDelegate.uuids.updateValue(uuid, forKey: "") - CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid) - Core.get().activateAudioSession(actived: true) - } else { - CallManager.instance().referedToCall = callId - } - } - } - break - case .End, - .Error: - var displayName = "Unknown" - if (call.dir == .Incoming) { - displayName = incomingDisplayName(call: call) - } else if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) { - displayName = contactName - } - - UIDevice.current.isProximityMonitoringEnabled = false - if (CallManager.instance().lc!.callsNb == 0) { - CallManager.instance().changeRouteToDefault() - // disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE; - // furthermore it introduces a bug when calling multiple times since route may not be - // reconfigured between cause leading to bluetooth being disabled while it should not - //CallManager.instance().bluetoothEnabled = false - } - - if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) { - // Configure the notification's payload. - let content = UNMutableNotificationContent() - content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil) - content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil) - - // Deliver the notification. - let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification. - let center = UNUserNotificationCenter.current() - center.add(request) { (error : Error?) in - if error != nil { - Log.directLog(BCTBX_LOG_ERROR, text: "Error while adding notification request : \(error!.localizedDescription)") - } - } - } - - if (CallManager.callKitEnabled()) { - var uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"] - if (callId == CallManager.instance().referedToCall) { - // refered call ended before connecting - Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered to call : \(String(describing: CallManager.instance().referedToCall))") - CallManager.instance().referedFromCall = nil - CallManager.instance().referedToCall = nil - } - if uuid == nil { - // the call not yet connected - uuid = CallManager.instance().providerDelegate.uuids[""] - } - if (uuid != nil) { - if (callId == CallManager.instance().referedFromCall) { - Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered from call : \(String(describing: CallManager.instance().referedFromCall))") - CallManager.instance().referedFromCall = nil - let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!] - callInfo!.callId = CallManager.instance().referedToCall ?? "" - CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!) - CallManager.instance().providerDelegate.uuids.removeValue(forKey: callId!) - CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId) - CallManager.instance().referedToCall = nil - break - } - if (endCallKitReplacedCall){ - let transaction = CXTransaction(action: - CXEndCallAction(call: uuid!)) - CallManager.instance().requestTransaction(transaction, action: "endCall") - }else{ - endCallKitReplacedCall = true - } - - } - } - break - case .Released: - CallManager.setAppData(sCall : call, appData : nil); - break - case .Referred: - CallManager.instance().referedFromCall = call.callLog?.callId - break - default: - break } - + let readyForRoutechange = CallManager.instance().callkitAudioSessionActivated == nil || (CallManager.instance().callkitAudioSessionActivated == true) if (readyForRoutechange && (cstate == .IncomingReceived || cstate == .OutgoingInit || cstate == .Connected || cstate == .StreamsRunning)) { if ((call.currentParams?.videoEnabled ?? false) && CallManager.instance().isReceiverEnabled() && call.conference == nil) { @@ -757,7 +757,7 @@ import AVFoundation AnyHashable("message"): message ]) } - + // Audio messages @objc func activateAudioSession() { @@ -778,7 +778,7 @@ import AVFoundation } return speakerCard != nil ? speakerCard : earpieceCard } - + // Local Conference @objc func startLocalConference() { @@ -789,18 +789,18 @@ import AVFoundation } let firstCall = calls!.first?.callLog?.callId ?? "" let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : "" - + let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"] if (currentUuid == nil) { Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.") return } - + let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"] let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid) let transcation = CXTransaction(action: groupAction) requestTransaction(transcation, action: "groupCall") - + setResumeCalls() } else { addAllToLocalConference()