> ## 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 React Native

<Info>
  **Quick Reference** - Initiate a call and listen for events:

  ```javascript theme={null}
  // Initiate a video call (default 45s no-answer timeout)
  const call = new CometChat.Call("RECEIVER_ID", CometChat.CALL_TYPE.VIDEO, CometChat.RECEIVER_TYPE.USER);
  await CometChat.initiateCall(call);

  // Initiate with custom timeout (60 seconds)
  await CometChat.initiateCall(call, 60);

  // Accept an incoming call
  await CometChat.acceptCall(sessionId);

  // Reject or cancel
  await CometChat.rejectCall(sessionId, CometChat.CALL_STATUS.REJECTED);
  ```
</Info>

<Note>
  Available via: [SDK](/calls/v4/react-native/ringing) | [REST API](/rest-api/calls) | [UI Kits](/ui-kit/react-native/call-features)
</Note>

## 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/react-native/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 generate a call token and render the `CometChatCalls.Component` 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="User Call (JavaScript)">
    ```javascript theme={null}
    const receiverID = "UID";
    const callType = CometChat.CALL_TYPE.VIDEO;
    const receiverType = CometChat.RECEIVER_TYPE.USER;

    const call = new CometChat.Call(receiverID, callType, receiverType);

    CometChat.initiateCall(call).then(
      (outgoingCall) => {
        console.log("Call initiated:", outgoingCall);
        // Show outgoing call UI
        // Store outgoingCall.getSessionId() for later use
      },
      (error) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="Group Call (JavaScript)">
    ```javascript theme={null}
    const receiverID = "GUID";
    const callType = CometChat.CALL_TYPE.VIDEO;
    const receiverType = CometChat.RECEIVER_TYPE.GROUP;

    const call = new CometChat.Call(receiverID, callType, receiverType);

    CometChat.initiateCall(call).then(
      (outgoingCall) => {
        console.log("Call initiated:", outgoingCall);
        // Show outgoing call UI
      },
      (error) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="User Call (TypeScript)">
    ```typescript theme={null}
    const receiverID: string = "UID";
    const callType: string = CometChat.CALL_TYPE.VIDEO;
    const receiverType: string = CometChat.RECEIVER_TYPE.USER;

    const call: CometChat.Call = new CometChat.Call(receiverID, callType, receiverType);

    CometChat.initiateCall(call).then(
      (outgoingCall: CometChat.Call) => {
        console.log("Call initiated:", outgoingCall);
      },
      (error: CometChat.CometChatException) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="Group Call (TypeScript)">
    ```typescript theme={null}
    const receiverID: string = "GUID";
    const callType: string = CometChat.CALL_TYPE.VIDEO;
    const receiverType: string = CometChat.RECEIVER_TYPE.GROUP;

    const call: CometChat.Call = new CometChat.Call(receiverID, callType, receiverType);

    CometChat.initiateCall(call).then(
      (outgoingCall: CometChat.Call) => {
        console.log("Call initiated:", outgoingCall);
      },
      (error: CometChat.CometChatException) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>
</Tabs>

| Parameter      | Description                                                       |
| -------------- | ----------------------------------------------------------------- |
| `receiverID`   | The UID or GUID of the recipient                                  |
| `receiverType` | `CometChat.RECEIVER_TYPE.USER` or `CometChat.RECEIVER_TYPE.GROUP` |
| `callType`     | `CometChat.CALL_TYPE.AUDIO` or `CometChat.CALL_TYPE.VIDEO`        |

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

By default, an unanswered call automatically cancels after 45 seconds. You can customize this duration by passing an optional `timeout` parameter (in seconds) as the second argument to `initiateCall()`.

<Tabs>
  <Tab title="User Call (JavaScript)">
    ```javascript theme={null}
    const receiverID = "UID";
    const callType = CometChat.CALL_TYPE.VIDEO;
    const receiverType = CometChat.RECEIVER_TYPE.USER;

    const call = new CometChat.Call(receiverID, callType, receiverType);

    // Set a custom timeout of 60 seconds
    CometChat.initiateCall(call, 60).then(
      (outgoingCall) => {
        console.log("Call initiated with 60s timeout:", outgoingCall);
      },
      (error) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="Group Call (JavaScript)">
    ```javascript theme={null}
    const receiverID = "GUID";
    const callType = CometChat.CALL_TYPE.VIDEO;
    const receiverType = CometChat.RECEIVER_TYPE.GROUP;

    const call = new CometChat.Call(receiverID, callType, receiverType);

    // Set a custom timeout of 60 seconds
    CometChat.initiateCall(call, 60).then(
      (outgoingCall) => {
        console.log("Call initiated with 60s timeout:", outgoingCall);
      },
      (error) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="User Call (TypeScript)">
    ```typescript theme={null}
    const receiverID: string = "UID";
    const callType: string = CometChat.CALL_TYPE.VIDEO;
    const receiverType: string = CometChat.RECEIVER_TYPE.USER;

    const call: CometChat.Call = new CometChat.Call(receiverID, callType, receiverType);

    // Set a custom timeout of 60 seconds
    CometChat.initiateCall(call, 60).then(
      (outgoingCall: CometChat.Call) => {
        console.log("Call initiated with 60s timeout:", outgoingCall);
      },
      (error: CometChat.CometChatException) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="Group Call (TypeScript)">
    ```typescript theme={null}
    const receiverID: string = "GUID";
    const callType: string = CometChat.CALL_TYPE.VIDEO;
    const receiverType: string = CometChat.RECEIVER_TYPE.GROUP;

    const call: CometChat.Call = new CometChat.Call(receiverID, callType, receiverType);

    // Set a custom timeout of 60 seconds
    CometChat.initiateCall(call, 60).then(
      (outgoingCall: CometChat.Call) => {
        console.log("Call initiated with 60s timeout:", outgoingCall);
      },
      (error: CometChat.CometChatException) => {
        console.log("Call initiation failed:", error);
      }
    );
    ```
  </Tab>
</Tabs>

| Parameter | Type     | Description                                                                                                    |
| --------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `call`    | `Call`   | The call object created with receiver ID, call type, and receiver type.                                        |
| `timeout` | `number` | Optional. The ringing duration in seconds before an unanswered call is automatically cancelled. Default: `45`. |

## 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="JavaScript">
    ```javascript theme={null}
    const listenerId = "UNIQUE_LISTENER_ID";

    CometChat.addCallListener(
      listenerId,
      new CometChat.CallListener({
        onIncomingCallReceived: (call) => {
          console.log("Incoming call:", call);
        },
        onOutgoingCallAccepted: (call) => {
          console.log("Outgoing call accepted:", call);
        },
        onOutgoingCallRejected: (call) => {
          console.log("Outgoing call rejected:", call);
        },
        onIncomingCallCancelled: (call) => {
          console.log("Incoming call cancelled:", call);
        },
        onCallEndedMessageReceived: (call) => {
          console.log("Call ended message:", call);
        }
      })
    );

    CometChat.removeCallListener(listenerId);
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const listenerId: string = "UNIQUE_LISTENER_ID";

    CometChat.addCallListener(
      listenerId,
      new CometChat.CallListener({
        onIncomingCallReceived: (call: CometChat.Call) => {
          console.log("Incoming call:", call);
        },
        onOutgoingCallAccepted: (call: CometChat.Call) => {
          console.log("Outgoing call accepted:", call);
        },
        onOutgoingCallRejected: (call: CometChat.Call) => {
          console.log("Outgoing call rejected:", call);
        },
        onIncomingCallCancelled: (call: CometChat.Call) => {
          console.log("Incoming call cancelled:", call);
        },
        onCallEndedMessageReceived: (call: CometChat.Call) => {
          console.log("Call ended message:", call);
        }
      })
    );

    CometChat.removeCallListener(listenerId);
    ```
  </Tab>
</Tabs>

<Warning>
  Always remove call listeners when the component unmounts using `CometChat.removeCallListener(listenerId)`. Failing to do so can cause memory leaks and duplicate event handling.
</Warning>

### Events

| Event                              | Description                                                                                               |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `onIncomingCallReceived(call)`     | Invoked when an incoming call is received. Display incoming call UI here.                                 |
| `onOutgoingCallAccepted(call)`     | Invoked on the caller's device when the receiver accepts. Generate call token and start the session here. |
| `onOutgoingCallRejected(call)`     | Invoked on the caller's device when the receiver rejects the call. Dismiss outgoing call UI here.         |
| `onIncomingCallCancelled(call)`    | Invoked on the receiver's device when the caller cancels before answering. Dismiss incoming call UI here. |
| `onCallEndedMessageReceived(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.

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    const sessionId = call.getSessionId();

    CometChat.acceptCall(sessionId).then(
      (call) => {
        console.log("Call accepted:", call);
        // Call accepted, now start the call session
      },
      (error) => {
        console.log("Accept call failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sessionId: string = call.getSessionId();

    CometChat.acceptCall(sessionId).then(
      (call: CometChat.Call) => {
        console.log("Call accepted:", call);
      },
      (error: CometChat.CometChatException) => {
        console.log("Accept call failed:", error);
      }
    );
    ```
  </Tab>
</Tabs>

## Reject Call

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

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    const sessionId = call.getSessionId();
    const status = CometChat.CALL_STATUS.REJECTED;

    CometChat.rejectCall(sessionId, status).then(
      (call) => {
        console.log("Call rejected:", call);
      },
      (error) => {
        console.log("Reject call failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sessionId: string = call.getSessionId();
    const status: string = CometChat.CALL_STATUS.REJECTED;

    CometChat.rejectCall(sessionId, status).then(
      (call: CometChat.Call) => {
        console.log("Call rejected:", call);
      },
      (error: CometChat.CometChatException) => {
        console.log("Reject call failed:", error);
      }
    );
    ```
  </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="JavaScript">
    ```javascript theme={null}
    const sessionId = call.getSessionId();
    const status = CometChat.CALL_STATUS.CANCELLED;

    CometChat.rejectCall(sessionId, status).then(
      (call) => {
        console.log("Call cancelled:", call);
      },
      (error) => {
        console.log("Cancel call failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sessionId: string = call.getSessionId();
    const status: string = CometChat.CALL_STATUS.CANCELLED;

    CometChat.rejectCall(sessionId, status).then(
      (call: CometChat.Call) => {
        console.log("Call cancelled:", call);
      },
      (error: CometChat.CometChatException) => {
        console.log("Cancel call failed:", error);
      }
    );
    ```
  </Tab>
</Tabs>

## Start Call Session

Once the call is accepted, both participants need to start the call session. See the [Call Session](/calls/v4/react-native/call-session#start-call-session) guide for full details.

## End Call

To end an active call in the ringing flow, call `CometChat.endCall()` in the `onCallEndButtonPressed()` callback, then call `CometChat.clearActiveCall()` and `CometChatCalls.endSession()`.

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    onCallEndButtonPressed: () => {
      CometChat.endCall(sessionId).then(
        (call) => {
          console.log("Call ended successfully");
          CometChat.clearActiveCall();
          CometChatCalls.endSession();
        },
        (error) => {
          console.log("End call failed:", error);
        }
      );
    }
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    onCallEndButtonPressed: () => {
      CometChat.endCall(sessionId).then(
        (call: CometChat.Call) => {
          console.log("Call ended successfully");
          CometChat.clearActiveCall();
          CometChatCalls.endSession();
        },
        (error: CometChat.CometChatException) => {
          console.log("End call failed:", error);
        }
      );
    }
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    onCallEnded: () => {
      CometChat.clearActiveCall();
      CometChatCalls.endSession();
    }
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    onCallEnded: () => {
      CometChat.clearActiveCall();
      CometChatCalls.endSession();
    }
    ```
  </Tab>
</Tabs>

For more details, see the [End Call Session](/calls/v4/react-native/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="JavaScript">
    ```javascript theme={null}
    const sessionId = call.getSessionId();
    const status = CometChat.CALL_STATUS.BUSY;

    CometChat.rejectCall(sessionId, status).then(
      (call) => {
        console.log("Busy status sent:", call);
      },
      (error) => {
        console.log("Busy rejection failed:", error);
      }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sessionId: string = call.getSessionId();
    const status: string = CometChat.CALL_STATUS.BUSY;

    CometChat.rejectCall(sessionId, status).then(
      (call: CometChat.Call) => {
        console.log("Busy status sent:", call);
      },
      (error: CometChat.CometChatException) => {
        console.log("Busy rejection failed:", error);
      }
    );
    ```
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Best Practices">
    * Always remove call listeners on component unmount to prevent memory leaks and duplicate events
    * Store the `sessionId` from `initiateCall()` or `onIncomingCallReceived()` — you'll need it for accept, reject, cancel, and starting the session
    * Handle the `CALL_STATUS_BUSY` case when the receiver is already on another call
    * Call `CometChat.clearActiveCall()` and `CometChatCalls.endSession()` together when a call ends to properly release all resources
    * Request camera and microphone permissions before initiating or accepting a call
  </Accordion>

  <Accordion title="Troubleshooting">
    * **`onIncomingCallReceived` not firing:** Ensure `CometChat.addCallListener()` is registered before the call is initiated and that the listener ID is unique
    * **Call accepted but no audio/video:** After `acceptCall()`, you must start the call session by generating a token and rendering `CometChatCalls.Component` — see the [Call Session](/calls/v4/react-native/call-session) guide
    * **Duplicate call events:** You may have registered the same listener multiple times — always call `CometChat.removeCallListener(listenerId)` on unmount
    * **`initiateCall` fails with error:** Verify the receiver UID/GUID exists and that the logged-in user has an active session
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Call Session" icon="video" href="/calls/v4/react-native/call-session">
    Start and manage the actual call session after the ringing flow completes.
  </Card>

  <Card title="Calls SDK Setup" icon="gear" href="/calls/v4/react-native/setup">
    Install dependencies, configure permissions, and initialize the Calls SDK.
  </Card>

  <Card title="Recording" icon="circle-dot" href="/calls/v4/react-native/recording">
    Record audio and video calls for playback or compliance.
  </Card>

  <Card title="Call Logs" icon="list" href="/calls/v4/react-native/call-logs">
    Retrieve and display call history including duration and participants.
  </Card>
</CardGroup>
