Skip to main content
Implement incoming and outgoing call notifications with accept/reject functionality. Ringing enables real-time call signaling between users, allowing them to initiate calls and respond to incoming call requests.
Ringing functionality requires the CometChat Chat SDK to be integrated alongside the Calls SDK. The Chat SDK handles call signaling (initiating, accepting, rejecting calls), while the Calls SDK manages the actual call session.

How Ringing Works

The ringing flow involves two SDKs working together:
  1. Chat SDK - Handles call signaling (initiate, accept, reject, cancel)
  2. Calls SDK - Manages the actual call session once accepted

Initiate a Call

Use the Chat SDK to initiate a call to a user or group:
let receiverID = "USER_ID"
let receiverType: CometChat.ReceiverType = .user
let callType: CometChat.CallType = .video

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

CometChat.initiateCall(call: call, onSuccess: { call in
    print("Call initiated: \(call?.sessionID ?? "")")
    // Show outgoing call UI
}, onError: { error in
    print("Call initiation failed: \(error?.errorDescription ?? "")")
})
ParameterTypeDescription
receiverIDStringUID of the user or GUID of the group to call
receiverTypeReceiverType.user or .group
callTypeCallType.video or .audio

Listen for Incoming Calls

Register a call listener to receive incoming call notifications:
let listenerID = "UNIQUE_LISTENER_ID"

CometChat.addCallListener(listenerID, self)

// Implement CometChatCallDelegate
extension CallViewController: CometChatCallDelegate {
    
    func onIncomingCallReceived(incomingCall: Call?, error: CometChatException?) {
        guard let call = incomingCall else { return }
        print("Incoming call from: \(call.callInitiator?.name ?? "")")
        // Show incoming call UI with accept/reject options
    }

    func onOutgoingCallAccepted(acceptedCall: Call?, error: CometChatException?) {
        guard let call = acceptedCall else { return }
        print("Call accepted, joining session...")
        joinCallSession(sessionId: call.sessionID ?? "")
    }

    func onOutgoingCallRejected(rejectedCall: Call?, error: CometChatException?) {
        print("Call rejected")
        // Dismiss outgoing call UI
    }

    func onIncomingCallCancelled(cancelledCall: Call?, error: CometChatException?) {
        print("Incoming call cancelled")
        // Dismiss incoming call UI
    }

    func onCallEndedMessageReceived(endedCall: Call?, error: CometChatException?) {
        print("Call ended")
    }
}
CallbackDescription
onIncomingCallReceivedA new incoming call is received
onOutgoingCallAcceptedThe receiver accepted your outgoing call
onOutgoingCallRejectedThe receiver rejected your outgoing call
onIncomingCallCancelledThe caller cancelled the incoming call
onCallEndedMessageReceivedThe call has ended
Remember to remove the call listener when it’s no longer needed to prevent memory leaks:
CometChat.removeCallListener(listenerID)

Accept a Call

When an incoming call is received, accept it using the Chat SDK:
func acceptIncomingCall(sessionId: String) {
    CometChat.acceptCall(sessionID: sessionId, onSuccess: { call in
        print("Call accepted")
        self.joinCallSession(sessionId: call?.sessionID ?? "")
    }, onError: { error in
        print("Accept call failed: \(error?.errorDescription ?? "")")
    })
}

Reject a Call

Reject an incoming call:
func rejectIncomingCall(sessionId: String) {
    let status: CometChat.CallStatus = .rejected

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

Cancel a Call

Cancel an outgoing call before it’s answered:
func cancelOutgoingCall(sessionId: String) {
    let status: CometChat.CallStatus = .cancelled

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

Join the Call Session

After accepting a call (or when your outgoing call is accepted), join the call session using the Calls SDK:
func joinCallSession(sessionId: String) {
    let sessionSettings = CometChatCalls.sessionSettingsBuilder
        .setType(.video)
        .build()

    CometChatCalls.joinSession(
        sessionID: sessionId,
        callSetting: sessionSettings,
        container: callViewContainer,
        onSuccess: { message in
            print("Joined call session")
        },
        onError: { error in
            print("Failed to join: \(error?.errorDescription ?? "")")
        }
    )
}

End a Call

Properly ending a call requires coordination between both SDKs to ensure all participants are notified and call logs are recorded correctly.
Always call CometChat.endCall() when ending a call. This notifies the other participant and ensures the call is properly logged. Without this, the other user won’t know the call has ended and call logs may be incomplete.
When using the default call UI, listen for the end call button click using ButtonClickListener and call endCall():
class CallViewController: UIViewController, ButtonClickListener {
    
    var currentSessionId: String = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CallSession.shared.addButtonClickListener(self)
    }
    
    func onLeaveSessionButtonClicked() {
        endCall(sessionId: currentSessionId)
    }
    
    func endCall(sessionId: String) {
        // 1. Leave the call session (Calls SDK)
        CallSession.shared.leaveSession()

        // 2. Notify other participants (Chat SDK)
        CometChat.endCall(sessionID: sessionId, onSuccess: { call in
            print("Call ended successfully")
            self.navigationController?.popViewController(animated: true)
        }, onError: { error in
            print("End call failed: \(error?.errorDescription ?? "")")
            self.navigationController?.popViewController(animated: true)
        })
    }
    
    // Other ButtonClickListener callbacks...
}
The other participant receives onCallEndedMessageReceived callback and should leave the session:
func onCallEndedMessageReceived(endedCall: Call?, error: CometChatException?) {
    CallSession.shared.leaveSession()
    navigationController?.popViewController(animated: true)
}

Call Status Values

StatusDescription
initiatedCall has been initiated but not yet answered
ongoingCall is currently in progress
busyReceiver is busy on another call
rejectedReceiver rejected the call
cancelledCaller cancelled before receiver answered
endedCall ended normally
missedReceiver didn’t answer in time
unansweredCall was not answered