Telha Wasim
Telha Wasim

Reputation: 3

Swift CallKit delegate method CXEndCallAction is triggered when accpting the call

I am implementing Agora SDK, when pressing the accept button, I am joing the user with the channel, but as I press the accept button from CallKit, my CXEndCallAction is triggered, which ends the call immedicately. Why? I am not triggering the cancel button on CallKit. Below is my Call which is handling the CallKit.

class CallKitService: NSObject, ObservableObject {
    //MARK: - PROPERTIES -
    
    //Normal
    static let shared = CallKitService()
    private let callController = CXCallController()
    private let provider: CXProvider
    private let callObserver = CXCallObserver()
    private var activeCallUUID: UUID?
    private var audioPlayer: AVAudioPlayer?
    private var isVibrating = false
    //Published
    @Published var callAccepted: Bool = false
    
    //MARK: - INITIALIZER -
    override init() {
        let providerConfig = CXProviderConfiguration()
        
        providerConfig.supportsVideo = false
        providerConfig.maximumCallsPerCallGroup = 2
        providerConfig.supportedHandleTypes = [.generic]
        
        self.provider = CXProvider(configuration: providerConfig)
        super.init()
        self.provider.setDelegate(self, queue: nil)
    }
}

//MARK: - FUNCTIONS -
extension CallKitService {
    
    //MARK: - START CALL -
    func startCall(calleeName: String, completion: @escaping (UUID?) -> Void) {
        let callUUID = UUID()
        
        self.activeCallUUID = callUUID
        let handle = CXHandle(type: .generic, value: calleeName)
        let startCallAction = CXStartCallAction(call: callUUID, handle: handle)
        let transaction = CXTransaction(action: startCallAction)
        
        self.callController.request(transaction) { error in
            if let error = error {
                print("CallKit: Error starting call: \(error.localizedDescription)")
            } else {
                self.provider.reportOutgoingCall(with: callUUID, startedConnectingAt: nil)
                completion(callUUID)
            }
        }
    }
    
    //MARK: - REPORT CALL CONNECTED -
    func reportCallConnected(callUUID: UUID) {
        self.provider.reportOutgoingCall(with: callUUID, connectedAt: Date())
    }
    
    //MARK: - END CALL -
    func endCall() {
        guard let callUUID = self.activeCallUUID else { return }
        
        let endCallAction = CXEndCallAction(call: callUUID)
        let transaction = CXTransaction(action: endCallAction)
        
        self.callController.request(transaction) { error in
            if let error = error {
                print("CallKit: Error ending call \(error.localizedDescription)")
            } else {
                print("CallKit: Call ended successfully")
            }
        }
        
        // Reset active call UUID
        self.activeCallUUID = nil
        
        // Stop any ringtone/vibration
        self.stopRingtone()
        self.stopVibration()
        
        self.provider.reportCall(with: callUUID, endedAt: Date(), reason: .remoteEnded)
    }
    
    //MARK: - REPORT INCOMING CALL -
    func reportIncomingCall(uuid: UUID, callerName: String) {
        let update = CXCallUpdate()
        
        update.remoteHandle = CXHandle(type: .generic, value: callerName)
        update.hasVideo = false
        
        self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
            if error == nil {
                self.activeCallUUID = uuid
                self.startRingtone()
                self.startVibration()
            } else {
                print("CallKit: Failed to report incoming call \(error!.localizedDescription)")
            }
        }
    }
    
    //MARK: - HAS ACTIVE CALL -
    func hasActiveCall() -> Bool {
        return self.callObserver.calls.contains { $0.hasEnded == false }
    }
    
    //MARK: - START RINGTONE -
    func startRingtone() {
        AudioServicesPlaySystemSound(1003)
    }
    
    //MARK: - STOP RINGTONE -
    func stopRingtone() {
        AudioServicesDisposeSystemSoundID(1003)
    }
    
    //MARK: - START VIBRATING -
    func startVibration() {
        self.isVibrating = true
        DispatchQueue.global().async {
            while self.isVibrating {
                AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                Thread.sleep(forTimeInterval: 1.0)
            }
        }
    }
    
    //MARK: - STOP VIBRATING -
    func stopVibration() {
        self.isVibrating = false
    }
    
    //MARK: - CALL INCOMING -
    func callIncoming() {
        self.startRingtone()
        self.startVibration()
    }
}

//MARK: - CX PROVIDER DELEGATE METHODS -
extension CallKitService: CXProviderDelegate {
    
    func providerDidReset(_ provider: CXProvider) {
        if !(self.callAccepted) {
            self.endCall()
        }
    }
    
    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        guard let callUUID = self.activeCallUUID else {
            action.fail()
            return
        }
        
        print("CallKit: Call accepted with UUID \(callUUID)")

        self.stopRingtone()
        self.stopVibration()

        self.callAccepted = true

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            NotificationCenter.default.post(name: .callAcceptedNotification, object: callUUID)
        }

        action.fulfill()
    }
    
    func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
        if (AgoraService.shared.isUserInCall) {
            CallManager.shared.endCall()
            self.activeCallUUID = nil
        } else {
            NotificationCenter.default.post(name: .callRejectedNotification, object: nil)
        }
        
        action.fulfill()
    }
}

Upvotes: 0

Views: 21

Answers (0)

Related Questions