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 CALL_STATUS_REJECTED
Caller can cancel the call using rejectCall() with status CALL_STATUS_CANCELLED
Once accepted, both participants call startSession() to join the call
Register the CallListener to receive real-time call events. Each listener requires a unique listenerId string to prevent duplicate registrations and enable targeted removal.
Java
Kotlin
Report incorrect code
Copy
Ask AI
private String listenerId = "UNIQUE_LISTENER_ID";// Register listener (e.g., in onCreate or onResume)CometChat.addCallListener(listenerId, new CometChat.CallListener() { @Override public void onIncomingCallReceived(Call call) { // Show incoming call UI } @Override public void onOutgoingCallAccepted(Call call) { // Receiver accepted, start the call session } @Override public void onOutgoingCallRejected(Call call) { // Receiver rejected, dismiss outgoing call UI } @Override public void onIncomingCallCancelled(Call call) { // Caller cancelled, dismiss incoming call UI } @Override public void onCallEndedMessageReceived(Call call) { // Call ended by remote participant }});// Unregister listener (e.g., in onDestroy or onPause)CometChat.removeCallListener(listenerId);
Report incorrect code
Copy
Ask AI
val listenerId = "UNIQUE_LISTENER_ID"// Register listener (e.g., in onCreate or onResume)CometChat.addCallListener(listenerId, object : CometChat.CallListener() { override fun onIncomingCallReceived(call: Call) { // Show incoming call UI } override fun onOutgoingCallAccepted(call: Call) { // Receiver accepted, start the call session } override fun onOutgoingCallRejected(call: Call) { // Receiver rejected, dismiss outgoing call UI } override fun onIncomingCallCancelled(call: Call) { // Caller cancelled, dismiss incoming call UI } override fun onCallEndedMessageReceived(call: Call) { // Call ended by remote participant }})// Unregister listener (e.g., in onDestroy or onPause)CometChat.removeCallListener(listenerId)
Always remove call listeners when they’re no longer needed (e.g., in onDestroy() or when navigating away). Failing to remove listeners can cause memory leaks and duplicate event handling.
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.
Java
Kotlin
Report incorrect code
Copy
Ask AI
String sessionId = call.getSessionId();String userAuthToken = CometChat.getUserAuthToken();// Step 1: Generate call tokenCometChatCalls.generateToken(sessionId, userAuthToken, new CometChatCalls.CallbackListener<GenerateToken>() { @Override public void onSuccess(GenerateToken token) { // Step 2: Start the call session RelativeLayout videoContainer = findViewById(R.id.video_container); CallSettings callSettings = new CometChatCalls.CallSettingsBuilder(activity, videoContainer) .setDefaultLayoutEnable(true) .setIsAudioOnly(false) .build(); CometChatCalls.startSession(token, callSettings, new CometChatCalls.CallbackListener<String>() { @Override public void onSuccess(String s) { // Call session started } @Override public void onError(CometChatException e) { Log.e(TAG, "Start session failed: " + e.getMessage()); } }); } @Override public void onError(CometChatException e) { Log.e(TAG, "Token generation failed: " + e.getMessage()); }});
Report incorrect code
Copy
Ask AI
val sessionId = call.sessionIdval userAuthToken = CometChat.getUserAuthToken()// Step 1: Generate call tokenCometChatCalls.generateToken(sessionId, userAuthToken, object : CometChatCalls.CallbackListener<GenerateToken>() { override fun onSuccess(token: GenerateToken) { // Step 2: Start the call session val videoContainer: RelativeLayout = findViewById(R.id.video_container) val callSettings = CometChatCalls.CallSettingsBuilder(activity, videoContainer) .setDefaultLayoutEnable(true) .setIsAudioOnly(false) .build() CometChatCalls.startSession(token, callSettings, object : CometChatCalls.CallbackListener<String> { override fun onSuccess(s: String) { // Call session started } override fun onError(e: CometChatException) { Log.e(TAG, "Start session failed: ${e.message}") } }) } override fun onError(e: CometChatException) { Log.e(TAG, "Token generation failed: ${e.message}") }})
For more details on call settings and customization, see the Call Session guide.
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() to notify other participants. On success, call CometChat.clearActiveCall() and CometChatCalls.endSession() to release resources.
Java
Kotlin
Report incorrect code
Copy
Ask AI
@Overridepublic void onCallEndButtonPressed() { CometChat.endCall(sessionId, new CometChat.CallbackListener<Call>() { @Override public void onSuccess(Call call) { CometChat.clearActiveCall(); CometChatCalls.endSession(); // Close the calling screen } @Override public void onError(CometChatException e) { Log.e(TAG, "End call failed: " + e.getMessage()); } });}
Report incorrect code
Copy
Ask AI
override fun onCallEndButtonPressed() { CometChat.endCall(sessionId, object : CometChat.CallbackListener<Call>() { override fun onSuccess(call: Call) { CometChat.clearActiveCall() CometChatCalls.endSession() // Close the calling screen } override fun onError(e: CometChatException) { Log.e(TAG, "End call failed: ${e.message}") } })}
If the receiver is already on another call, you can reject the incoming call with CALL_STATUS_BUSY status.
Java
Kotlin
Report incorrect code
Copy
Ask AI
String sessionID = call.getSessionId();String status = CometChatConstants.CALL_STATUS_BUSY;CometChat.rejectCall(sessionID, status, new CometChat.CallbackListener<Call>() { @Override public void onSuccess(Call call) { // Busy status sent to caller } @Override public void onError(CometChatException e) { Log.e(TAG, "Busy rejection failed: " + e.getMessage()); }});
Report incorrect code
Copy
Ask AI
val sessionID = call.sessionIdval status = CometChatConstants.CALL_STATUS_BUSYCometChat.rejectCall(sessionID, status, object : CometChat.CallbackListener<Call>() { override fun onSuccess(call: Call) { // Busy status sent to caller } override fun onError(e: CometChatException) { Log.e(TAG, "Busy rejection failed: ${e.message}") }})
Remove call listeners in onDestroy() or onPause() to prevent memory leaks and duplicate callbacks. Use unique listener IDs to manage multiple listeners effectively.
Handle All Call States
Implement all call listener callbacks (onIncomingCallReceived, onOutgoingCallAccepted, onOutgoingCallRejected, onIncomingCallCancelled) to provide a complete user experience and handle edge cases.
Store Session ID
Store the sessionId from the Call object after initiating a call. You’ll need it for accepting, rejecting, canceling, and ending the call.
Show Appropriate UI States
Display different UI for incoming calls (accept/reject buttons), outgoing calls (cancel button), and active calls (end call button) to match user expectations.
Symptom:initiateCall() fails with “User not logged in” or “Invalid receiver” error.Cause: User not logged in or invalid receiver UID/GUID.Solution: Ensure CometChat.login() is called successfully before initiating calls. Verify the receiver UID or GUID exists using CometChat.getUser() or CometChat.getGroup().
Listener Not Receiving Events
Symptom: Call listener callbacks are not triggered when calls are received or accepted.Cause: Listener not registered or removed prematurely.Solution: Register the call listener in onCreate() or onResume() and ensure it’s not removed until onDestroy() or onPause(). Verify the listener ID is unique.
Call Session Won't Start
Symptom: After accepting a call, the call session doesn’t start or shows a black screen.Cause: Missing token generation or incorrect call settings.Solution: Ensure you call generateToken() and startSession() in the acceptCall() success callback. Verify the video container layout exists in your XML. See Call Session for details.