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:
- Caller initiates a call using
initiateCall()
- Receiver gets notified via
onIncomingCallReceived() callback
- Receiver can either:
- Accept the call using
acceptCall()
- Reject the call using
rejectCall() with status .rejected
- Caller can cancel the call using
rejectCall() with status .cancelled
- 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 ?? "")")
}
NSString *receiverID = @"UID";
Call *newCall = [[Call alloc] initWithReceiverId:receiverID callType:CallTypeVideo receiverType:ReceiverTypeUser];
[CometChat initiateCallWithCall:newCall onSuccess:^(Call *call) {
// Call initiated, show outgoing call UI
NSLog(@"Call initiated successfully");
} onError:^(CometChatException *error) {
NSLog(@"Call initiation failed: %@", [error errorDescription]);
}];
| Parameter | Description |
|---|
receiverID | The UID or GUID of the recipient |
receiverType | The type of the receiver: .user or .group |
callType | The 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
}
}
@interface ViewController () <CometChatCallDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[CometChat setCalldelegate:self];
}
- (void)onIncomingCallReceivedWithIncomingCall:(Call *)incomingCall error:(CometChatException *)error {
// Show incoming call UI
}
- (void)onOutgoingCallAcceptedWithAcceptedCall:(Call *)acceptedCall error:(CometChatException *)error {
// Receiver accepted, start the call session
}
- (void)onOutgoingCallRejectedWithRejectedCall:(Call *)rejectedCall error:(CometChatException *)error {
// Receiver rejected, dismiss outgoing call UI
}
- (void)onIncomingCallCanceledWithCanceledCall:(Call *)canceledCall error:(CometChatException *)error {
// Caller cancelled, dismiss incoming call UI
}
@end
Set your view controller as the CometChat call delegate in viewDidLoad(): CometChat.calldelegate = self
Events
| Event | Description |
|---|
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 ?? "")")
}
[CometChat acceptCallWithSessionID:incomingCall.sessionID onSuccess:^(Call *call) {
// Call accepted, now start the call session
NSLog(@"Call accepted successfully");
} onError:^(CometChatException *error) {
NSLog(@"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 ?? "")")
}
[CometChat rejectCallWithSessionID:incomingCall.sessionID status:callStatusRejected onSuccess:^(Call *call) {
// Call rejected, dismiss incoming call UI
NSLog(@"Call rejected successfully");
} onError:^(CometChatException *error) {
NSLog(@"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 ?? "")")
}
[CometChat rejectCallWithSessionID:outgoingCall.sessionID status:callStatusCancelled onSuccess:^(Call *call) {
// Call cancelled, dismiss outgoing call UI
NSLog(@"Call cancelled successfully");
} onError:^(CometChatException *error) {
NSLog(@"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 ?? "")")
}
[CometChat rejectCallWithSessionID:incomingCall.sessionID status:callStatusBusy onSuccess:^(Call *call) {
// Busy status sent to caller
NSLog(@"Busy rejection sent");
} onError:^(CometChatException *error) {
NSLog(@"Busy rejection failed: %@", [error errorDescription]);
}];