Skip to main content
Implement incoming and outgoing call notifications by integrating the Calls SDK with the CometChat Chat SDK for call signaling.
The Calls SDK handles the actual call session. For call signaling (ringing, accept, reject), use the CometChat Chat SDK’s calling features.

Overview

Call flow with ringing:
  1. Initiator sends a call request via Chat SDK
  2. Receiver gets notified of incoming call
  3. Receiver accepts or rejects the call
  4. Both parties join the call session using Calls SDK

Prerequisites

Install both SDKs:
npm install @cometchat/chat-sdk-javascript @cometchat/calls-sdk-javascript

Initialize Both SDKs

import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatCalls } from "@cometchat/calls-sdk-javascript";

const appId = "APP_ID";
const region = "REGION";

// Initialize Chat SDK
await CometChat.init(appId, new CometChat.AppSettingsBuilder()
  .subscribePresenceForAllUsers()
  .setRegion(region)
  .build()
);

// Initialize Calls SDK
await CometChatCalls.init({ appId, region });

// Login to both
await CometChat.login(uid, apiKey);
await CometChatCalls.login(uid, apiKey);

Initiate a Call

Start an outgoing call:
async function initiateCall(receiverUid, callType = "video") {
  const call = new CometChat.Call(
    receiverUid,
    callType === "video" ? CometChat.CALL_TYPE.VIDEO : CometChat.CALL_TYPE.AUDIO,
    CometChat.RECEIVER_TYPE.USER
  );

  try {
    const outgoingCall = await CometChat.initiateCall(call);
    console.log("Call initiated:", outgoingCall);
    
    // Show outgoing call UI
    showOutgoingCallScreen(outgoingCall);
    
    return outgoingCall;
  } catch (error) {
    console.error("Call initiation failed:", error);
    throw error;
  }
}

Listen for Incoming Calls

Register a call listener to receive incoming calls:
const callListenerId = "CALL_LISTENER_ID";

CometChat.addCallListener(
  callListenerId,
  new CometChat.CallListener({
    onIncomingCallReceived: (incomingCall) => {
      console.log("Incoming call:", incomingCall);
      showIncomingCallScreen(incomingCall);
    },
    onOutgoingCallAccepted: (acceptedCall) => {
      console.log("Call accepted:", acceptedCall);
      startCallSession(acceptedCall.getSessionId());
    },
    onOutgoingCallRejected: (rejectedCall) => {
      console.log("Call rejected:", rejectedCall);
      hideOutgoingCallScreen();
    },
    onIncomingCallCancelled: (cancelledCall) => {
      console.log("Call cancelled:", cancelledCall);
      hideIncomingCallScreen();
    },
    onCallEndedMessageReceived: (endedCall) => {
      console.log("Call ended:", endedCall);
    },
  })
);

Accept an Incoming Call

async function acceptCall(incomingCall) {
  try {
    const acceptedCall = await CometChat.acceptCall(incomingCall.getSessionId());
    console.log("Call accepted:", acceptedCall);
    
    // Start the call session
    startCallSession(acceptedCall.getSessionId());
  } catch (error) {
    console.error("Accept call failed:", error);
  }
}

Reject an Incoming Call

async function rejectCall(incomingCall, reason = CometChat.CALL_STATUS.REJECTED) {
  try {
    await CometChat.rejectCall(incomingCall.getSessionId(), reason);
    console.log("Call rejected");
    hideIncomingCallScreen();
  } catch (error) {
    console.error("Reject call failed:", error);
  }
}

Cancel an Outgoing Call

async function cancelCall(outgoingCall) {
  try {
    await CometChat.rejectCall(outgoingCall.getSessionId(), CometChat.CALL_STATUS.CANCELLED);
    console.log("Call cancelled");
    hideOutgoingCallScreen();
  } catch (error) {
    console.error("Cancel call failed:", error);
  }
}

Start the Call Session

Once the call is accepted, join the session using the Calls SDK:
async function startCallSession(sessionId) {
  const container = document.getElementById("call-container");
  
  try {
    // Generate token
    const tokenResult = await CometChatCalls.generateToken(sessionId);
    
    // Join session
    await CometChatCalls.joinSession(
      tokenResult.token,
      {
        sessionType: "VIDEO",
        layout: "TILE",
      },
      container
    );
    
    // Listen for session end
    CometChatCalls.addEventListener("onSessionLeft", () => {
      endCall(sessionId);
    });
  } catch (error) {
    console.error("Failed to start call session:", error);
  }
}

End the Call

async function endCall(sessionId) {
  try {
    // Leave the Calls SDK session
    CometChatCalls.leaveSession();
    
    // End the call in Chat SDK
    await CometChat.endCall(sessionId);
    
    console.log("Call ended");
  } catch (error) {
    console.error("End call failed:", error);
  }
}

Incoming Call UI Example

function showIncomingCallScreen(call) {
  const caller = call.getCallInitiator();
  
  const html = `
    <div id="incoming-call" class="incoming-call-overlay">
      <div class="incoming-call-card">
        <img src="${caller.getAvatar()}" alt="${caller.getName()}" />
        <h3>${caller.getName()}</h3>
        <p>Incoming ${call.getType()} call...</p>
        <div class="call-actions">
          <button onclick="rejectCall(currentCall)" class="reject-btn">Decline</button>
          <button onclick="acceptCall(currentCall)" class="accept-btn">Accept</button>
        </div>
      </div>
    </div>
  `;
  
  document.body.insertAdjacentHTML("beforeend", html);
  window.currentCall = call;
  
  // Play ringtone
  playRingtone();
}

function hideIncomingCallScreen() {
  document.getElementById("incoming-call")?.remove();
  stopRingtone();
}

Outgoing Call UI Example

function showOutgoingCallScreen(call) {
  const receiver = call.getCallReceiver();
  
  const html = `
    <div id="outgoing-call" class="outgoing-call-overlay">
      <div class="outgoing-call-card">
        <img src="${receiver.getAvatar()}" alt="${receiver.getName()}" />
        <h3>${receiver.getName()}</h3>
        <p>Calling...</p>
        <button onclick="cancelCall(currentCall)" class="cancel-btn">Cancel</button>
      </div>
    </div>
  `;
  
  document.body.insertAdjacentHTML("beforeend", html);
  window.currentCall = call;
  
  // Play ringback tone
  playRingbackTone();
}

function hideOutgoingCallScreen() {
  document.getElementById("outgoing-call")?.remove();
  stopRingbackTone();
}

Cleanup

Remove the call listener when no longer needed:
CometChat.removeCallListener(callListenerId);