> ## Documentation Index
> Fetch the complete documentation index at: https://www.cometchat.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Ringing

> CometChat Calling SDK v4 - Stable Release - Ringing for Android

## 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**.

<Note>
  After the call is accepted, you need to start the call session. See the [Call Session](/calls/v4/android/call-session#start-call-session) guide for details on starting and managing the actual call.
</Note>

**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 `CALL_STATUS_REJECTED`
4. **Caller** can cancel the call using `rejectCall()` with status `CALL_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.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverID = "UID";
    String receiverType = CometChatConstants.RECEIVER_TYPE_USER;
    String callType = CometChatConstants.CALL_TYPE_VIDEO;

    Call call = new Call(receiverID, receiverType, callType);

    CometChat.initiateCall(call, new CometChat.CallbackListener<Call>() {
        @Override
        public void onSuccess(Call call) {
            // Call initiated, show outgoing call UI
            // Store call.getSessionId() for later use
        }

        @Override
        public void onError(CometChatException e) {
            Log.e(TAG, "Call initiation failed: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverID = "UID"
    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) {
            // Call initiated, show outgoing call UI
            // Store call.sessionId for later use
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Call initiation failed: ${e.message}")
        }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    String receiverID = "GUID";
    String receiverType = CometChatConstants.RECEIVER_TYPE_GROUP;
    String callType = CometChatConstants.CALL_TYPE_VIDEO;

    Call call = new Call(receiverID, receiverType, callType);

    CometChat.initiateCall(call, new CometChat.CallbackListener<Call>() {
        @Override
        public void onSuccess(Call call) {
            // Call initiated, show outgoing call UI
        }

        @Override
        public void onError(CometChatException e) {
            Log.e(TAG, "Call initiation failed: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val receiverID = "GUID"
    val receiverType = CometChatConstants.RECEIVER_TYPE_GROUP
    val callType = CometChatConstants.CALL_TYPE_VIDEO

    val call = Call(receiverID, receiverType, callType)

    CometChat.initiateCall(call, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            // Call initiated, show outgoing call UI
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Call initiation failed: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

| Parameter      | Description                                                                                                   |
| -------------- | ------------------------------------------------------------------------------------------------------------- |
| `receiverID`   | The UID or GUID of the recipient                                                                              |
| `receiverType` | The type of the receiver: `CometChatConstants.RECEIVER_TYPE_USER` or `CometChatConstants.RECEIVER_TYPE_GROUP` |
| `callType`     | The type of the call: `CometChatConstants.CALL_TYPE_AUDIO` or `CometChatConstants.CALL_TYPE_VIDEO`            |

On success, a `Call` object is returned containing the call details including a unique `sessionId` required for starting the call session.

## Call Listeners

Register the `CallListener` to receive real-time call events. Each listener requires a unique `listenerId` string to prevent duplicate registrations and enable targeted removal.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    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);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    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)
    ```
  </Tab>
</Tabs>

### Events

| Event                                    | Description                                                                                                                              |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `onIncomingCallReceived(call: Call)`     | Invoked when an incoming call is received. The `call` contains caller details, session ID, and call type. Display incoming call UI here. |
| `onOutgoingCallAccepted(call: Call)`     | Invoked on the caller's device when the receiver accepts. Generate call token and start the session here.                                |
| `onOutgoingCallRejected(call: Call)`     | Invoked on the caller's device when the receiver rejects the call. Dismiss outgoing call UI here.                                        |
| `onIncomingCallCancelled(call: Call)`    | Invoked on the receiver's device when the caller cancels before answering. Dismiss incoming call UI here.                                |
| `onCallEndedMessageReceived(call: Call)` | Invoked when a call ends. The `call` contains final status and duration. 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.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    String sessionID = call.getSessionId(); // From onIncomingCallReceived

    CometChat.acceptCall(sessionID, new CometChat.CallbackListener<Call>() {
        @Override
        public void onSuccess(Call call) {
            // Call accepted, now start the call session
            // Generate token and call startSession()
        }

        @Override
        public void onError(CometChatException e) {
            Log.e(TAG, "Accept call failed: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionID = call.sessionId // From onIncomingCallReceived

    CometChat.acceptCall(sessionID, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            // Call accepted, now start the call session
            // Generate token and call startSession()
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Accept call failed: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

## Reject Call

Use `rejectCall()` to reject an incoming call. Set the status to `CALL_STATUS_REJECTED`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    String sessionID = call.getSessionId();
    String status = CometChatConstants.CALL_STATUS_REJECTED;

    CometChat.rejectCall(sessionID, status, new CometChat.CallbackListener<Call>() {
        @Override
        public void onSuccess(Call call) {
            // Call rejected, dismiss incoming call UI
        }

        @Override
        public void onError(CometChatException e) {
            Log.e(TAG, "Reject call failed: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionID = call.sessionId
    val status = CometChatConstants.CALL_STATUS_REJECTED

    CometChat.rejectCall(sessionID, status, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            // Call rejected, dismiss incoming call UI
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Reject call failed: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

## Cancel Call

The caller can cancel an outgoing call before it's answered using `rejectCall()` with status `CALL_STATUS_CANCELLED`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    String sessionID = call.getSessionId();
    String status = CometChatConstants.CALL_STATUS_CANCELLED;

    CometChat.rejectCall(sessionID, status, new CometChat.CallbackListener<Call>() {
        @Override
        public void onSuccess(Call call) {
            // Call cancelled, dismiss outgoing call UI
        }

        @Override
        public void onError(CometChatException e) {
            Log.e(TAG, "Cancel call failed: " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionID = call.sessionId
    val status = CometChatConstants.CALL_STATUS_CANCELLED

    CometChat.rejectCall(sessionID, status, object : CometChat.CallbackListener<Call>() {
        override fun onSuccess(call: Call) {
            // Call cancelled, dismiss outgoing call UI
        }

        override fun onError(e: CometChatException) {
            Log.e(TAG, "Cancel call failed: ${e.message}")
        }
    })
    ```
  </Tab>
</Tabs>

## 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.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    String sessionId = call.getSessionId();
    String userAuthToken = CometChat.getUserAuthToken();

    // Step 1: Generate call token
    CometChatCalls.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());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionId = call.sessionId
    val userAuthToken = CometChat.getUserAuthToken()

    // Step 1: Generate call token
    CometChatCalls.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}")
        }
    })
    ```
  </Tab>
</Tabs>

For more details on call settings and customization, see the [Call Session](/calls/v4/android/call-session#start-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()` to notify other participants. On success, call `CometChat.clearActiveCall()` and `CometChatCalls.endSession()` to release resources.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    @Override
    public 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());
            }
        });
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    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}")
            }
        })
    }
    ```
  </Tab>
</Tabs>

**Remote participant** (receives `onCallEnded()` callback):

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    @Override
    public void onCallEnded() {
        CometChat.clearActiveCall();
        CometChatCalls.endSession();
        // Close the calling screen
    }
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    override fun onCallEnded() {
        CometChat.clearActiveCall()
        CometChatCalls.endSession()
        // Close the calling screen
    }
    ```
  </Tab>
</Tabs>

For more details, see the [End Call Session](/calls/v4/android/call-session#end-call-session) guide.

## Busy Call Handling

If the receiver is already on another call, you can reject the incoming call with `CALL_STATUS_BUSY` status.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    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());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionID = call.sessionId
    val status = CometChatConstants.CALL_STATUS_BUSY

    CometChat.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}")
        }
    })
    ```
  </Tab>
</Tabs>
