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:
val receiverID = "USER_ID"
val receiverType = CometChatConstants.RECEIVER_TYPE_USER
val callType = CometChatConstants.CALL_TYPE_VIDEO

val call = Call(receiverID, receiverType, callType)

CometChat.initiateCall(call, object : CometChat.CallbackListener<Call>() {
    override fun onSuccess(call: Call) {
        Log.d(TAG, "Call initiated: ${call.sessionId}")
        // Show outgoing call UI
    }

    override fun onError(e: CometChatException) {
        Log.e(TAG, "Call initiation failed: ${e.message}")
    }
})
ParameterTypeDescription
receiverIDStringUID of the user or GUID of the group to call
receiverTypeStringCometChatConstants.RECEIVER_TYPE_USER or RECEIVER_TYPE_GROUP
callTypeStringCometChatConstants.CALL_TYPE_VIDEO or CALL_TYPE_AUDIO

Listen for Incoming Calls

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

CometChat.addCallListener(listenerID, object : CometChat.CallListener() {
    override fun onIncomingCallReceived(call: Call) {
        Log.d(TAG, "Incoming call from: ${call.callInitiator.name}")
        // Show incoming call UI with accept/reject options
    }

    override fun onOutgoingCallAccepted(call: Call) {
        Log.d(TAG, "Call accepted, joining session...")
        joinCallSession(call.sessionId)
    }

    override fun onOutgoingCallRejected(call: Call) {
        Log.d(TAG, "Call rejected")
        // Dismiss outgoing call UI
    }

    override fun onIncomingCallCancelled(call: Call) {
        Log.d(TAG, "Incoming call cancelled")
        // Dismiss incoming call UI
    }

    override fun onCallEndedMessageReceived(call: Call) {
        Log.d(TAG, "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:
fun acceptIncomingCall(sessionId: String) {
    CometChat.acceptCall(sessionId, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            Log.d(TAG, "Call accepted")
            joinCallSession(call.sessionId)
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Accept call failed: ${e.message}")
        }
    })
}

Reject a Call

Reject an incoming call:
fun rejectIncomingCall(sessionId: String) {
    val status = CometChatConstants.CALL_STATUS_REJECTED

    CometChat.rejectCall(sessionId, status, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            Log.d(TAG, "Call rejected")
            // Dismiss incoming call UI
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Reject call failed: ${e.message}")
        }
    })
}

Cancel a Call

Cancel an outgoing call before it’s answered:
fun cancelOutgoingCall(sessionId: String) {
    val status = CometChatConstants.CALL_STATUS_CANCELLED

    CometChat.rejectCall(sessionId, status, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            Log.d(TAG, "Call cancelled")
            // Dismiss outgoing call UI
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Cancel call failed: ${e.message}")
        }
    })
}

Join the Call Session

After accepting a call (or when your outgoing call is accepted), join the call session using the Calls SDK:
fun joinCallSession(sessionId: String) {
    val callViewContainer = findViewById<RelativeLayout>(R.id.call_view_container)

    val sessionSettings = CometChatCalls.SessionSettingsBuilder()
        .setType(SessionType.VIDEO)
        .build()

    CometChatCalls.joinSession(sessionId, sessionSettings, callViewContainer,
        object : CometChatCalls.CallbackListener<CallSession>() {
            override fun onSuccess(callSession: CallSession) {
                Log.d(TAG, "Joined call session")
            }

            override fun onError(e: CometChatException) {
                Log.e(TAG, "Failed to join: ${e.message}")
            }
        }
    )
}
For more details on session customization and controlling the call, see Actions and Listeners.

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():
val callSession = CallSession.getInstance()

// Listen for end call button click
callSession.addButtonClickListener(this, object : ButtonClickListener() {
    override fun onLeaveSessionButtonClicked() {
        endCall(currentSessionId)
    }
    // Other callbacks...
})

fun endCall(sessionId: String) {
    // 1. Leave the call session (Calls SDK)
    CallSession.getInstance().leaveSession()

    // 2. Notify other participants (Chat SDK)
    CometChat.endCall(sessionId, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            Log.d(TAG, "Call ended successfully")
            finish()
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "End call failed: ${e.message}")
            finish()
        }
    })
}
The other participant receives onCallEndedMessageReceived callback and should leave the session:
CometChat.addCallListener(listenerID, object : CometChat.CallListener() {
    override fun onCallEndedMessageReceived(call: Call) {
        CallSession.getInstance().leaveSession()
        finish()
    }
    // Other callbacks...
})

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