Skip to main content

Overview

This section explains how to implement a complete calling workflow with ringing functionality, including incoming/outgoing call UI, call acceptance, rejection, and cancellation. Previously known as Default Calling.
After the call is accepted, you need to start the call session. See the Call Session guide for details on starting and managing the actual call.
Call Flow:
  1. Caller initiates a call using initiateCall()
  2. Receiver gets notified via onIncomingCallReceived() callback
  3. Receiver can either:
    • Accept the call using acceptCall()
    • Reject the call using rejectCall() with status .rejected
  4. Caller can cancel the call using rejectCall() with status .cancelled
  5. Once accepted, both participants call startSession() to join the call

Initiate Call

The initiateCall() method sends a call request to a user or a group. On success, the receiver gets an onIncomingCallReceived() callback.
let receiverID = "UID"
let receiverType: CometChat.ReceiverType = .user // or .group
let callType: CometChat.CallType = .video // or .audio

let newCall = Call(receiverId: receiverID, callType: callType, receiverType: receiverType)

CometChat.initiateCall(call: newCall, onSuccess: { call in
    // Call initiated, show outgoing call UI
    // Store call.sessionID for later use
    print("Call initiated successfully")
}) { error in
    print("Call initiation failed: \(error?.errorDescription ?? "")")
}
ParameterDescription
receiverIDThe UID or GUID of the recipient
receiverTypeThe type of the receiver: .user or .group
callTypeThe type of the call: .audio or .video

Call Listeners

Register the CometChatCallDelegate to receive real-time call events.
extension ViewController: CometChatCallDelegate {
    
    func onIncomingCallReceived(incomingCall: Call?, error: CometChatException?) {
        // Show incoming call UI
    }
    
    func onOutgoingCallAccepted(acceptedCall: Call?, error: CometChatException?) {
        // Receiver accepted, start the call session
    }
    
    func onOutgoingCallRejected(rejectedCall: Call?, error: CometChatException?) {
        // Receiver rejected, dismiss outgoing call UI
    }
    
    func onIncomingCallCanceled(canceledCall: Call?, error: CometChatException?) {
        // Caller cancelled, dismiss incoming call UI
    }
    
    func onCallEndedMessageReceived(endedCall: Call?, error: CometChatException?) {
        // Call ended by remote participant
    }
}
Set your view controller as the CometChat call delegate in viewDidLoad(): CometChat.calldelegate = self

Events

EventDescription
onIncomingCallReceived(incomingCall: Call)Invoked when an incoming call is received. Display incoming call UI here.
onOutgoingCallAccepted(acceptedCall: Call)Invoked on the caller’s device when the receiver accepts. Start the call session here.
onOutgoingCallRejected(rejectedCall: Call)Invoked on the caller’s device when the receiver rejects. Dismiss outgoing call UI.
onIncomingCallCanceled(canceledCall: Call)Invoked on the receiver’s device when the caller cancels. Dismiss incoming call UI.
onCallEndedMessageReceived(endedCall: Call)Invoked when a call ends. Update call history here.

Accept Call

When an incoming call is received via onIncomingCallReceived(), use acceptCall() to accept it. On success, start the call session.
let sessionID = incomingCall?.sessionID ?? ""

CometChat.acceptCall(sessionID: sessionID, onSuccess: { call in
    // Call accepted, now start the call session
    print("Call accepted successfully")
}) { error in
    print("Accept call failed: \(error?.errorDescription ?? "")")
}

Reject Call

Use rejectCall() to reject an incoming call. Set the status to .rejected.
let sessionID = incomingCall?.sessionID ?? ""
let status: CometChatConstants.callStatus = .rejected

CometChat.rejectCall(sessionID: sessionID, status: status, onSuccess: { call in
    // Call rejected, dismiss incoming call UI
    print("Call rejected successfully")
}) { error in
    print("Reject call failed: \(error?.errorDescription ?? "")")
}

Cancel Call

The caller can cancel an outgoing call before it’s answered using rejectCall() with status .cancelled.
let sessionID = outgoingCall?.sessionID ?? ""
let status: CometChatConstants.callStatus = .cancelled

CometChat.rejectCall(sessionID: sessionID, status: status, onSuccess: { call in
    // Call cancelled, dismiss outgoing call UI
    print("Call cancelled successfully")
}) { error in
    print("Cancel call failed: \(error?.errorDescription ?? "")")
}

Start Call Session

Once the call is accepted, both participants need to start the call session. Caller flow: In the onOutgoingCallAccepted() callback, generate a token and start the session. Receiver flow: In the acceptCall() success callback, generate a token and start the session.
let sessionId = call?.sessionID ?? ""
let authToken = CometChat.getUserAuthToken() ?? ""

// Step 1: Generate call token
CometChatCalls.generateToken(authToken: authToken as NSString, sessionID: sessionId) { token in
    
    // Step 2: Configure call settings
    let callSettings = CometChatCalls.CallSettingsBuilder
        .setDefaultLayout(true)
        .setIsAudioOnly(false)
        .setDelegate(self)
        .build()
    
    // Step 3: Start the call session
    CometChatCalls.startSession(callToken: token, callSetting: callSettings, view: self.callView) { success in
        print("Call session started successfully")
    } onError: { error in
        print("Start session failed: \(String(describing: error?.errorDescription))")
    }
    
} onError: { error in
    print("Token generation failed: \(String(describing: error?.errorDescription))")
}
For more details on call settings and customization, see the Call Session guide.

End Call

To end an active call in the ringing flow, the process differs based on who ends the call. User who ends the call: When the user presses the end call button, the onCallEndButtonPressed() callback is triggered. Inside this callback, call CometChat.endCall(). On success, call CometChat.clearActiveCall() and CometChatCalls.endSession().
func onCallEndButtonPressed() {
    CometChat.endCall(sessionID: sessionId) { call in
        CometChat.clearActiveCall()
        CometChatCalls.endSession()
        // Close the calling screen
    } onError: { error in
        print("End call failed: \(String(describing: error?.errorDescription))")
    }
}
Remote participant (receives onCallEnded() callback):
func onCallEnded() {
    CometChat.clearActiveCall()
    CometChatCalls.endSession()
    // Close the calling screen
}
For more details, see the End Call Session guide.

Busy Call Handling

If the receiver is already on another call, you can reject the incoming call with .busy status.
let sessionID = incomingCall?.sessionID ?? ""
let status: CometChatConstants.callStatus = .busy

CometChat.rejectCall(sessionID: sessionID, status: status, onSuccess: { call in
    // Busy status sent to caller
    print("Busy rejection sent")
}) { error in
    print("Busy rejection failed: \(error?.errorDescription ?? "")")
}