Reputation: 3
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