Make your first call
Call SDK for Web adds 1-to-1 and group voice and video calling to your app.
Call SDK supports 1-to-1 calls and group calls. Follow this guide to build both flows from scratch.
Environment requirements
Your browser page must use HTTPS, or run on the localhost domain.
Prerequisites
Each app has two separate App Keys, one for the development environment and one for the production environment. Data is isolated between the two environments. Before you launch your app, switch to the production App Key for end-to-end testing and final rollout.
- Go to the Console and register a developer account. After registration, the console automatically creates an app in the development environment.
- On the Key Management page, get your App Key for the development environment. You can also find your App Secret and data center on the same page.
- Enable the audio and video calling service.
Quickstart
Follow these steps to integrate audio and video calling.
Step 1: Install the SDK
Call SDK for Web depends on @nexconn/engine, @nexconn/chat, and @nexconn/call.
NPM
Install the required packages:
npm install @nexconn/engine @nexconn/chat @nexconn/call
Import and initialize them in an ES6 module:
import { NCEngine } from '@nexconn/chat';
import { NCCallEngine } from '@nexconn/call';
If you use TypeScript, set --esModuleInterop to true for default imports, or use named imports based on each package's exports, such as import { NCCallEngine } from '@nexconn/call'.
Step 2: Request access to media devices
Call SDK for Web needs access to the microphone and camera. Run navigator.mediaDevices.getUserMedia({ audio: true, video: true }) in the browser console on your integration page. The browser might prompt the user to grant access.
Step 3: Initialize with your App Key
Call SDK uses Engine to establish the signaling connection with Nexconn. To integrate and run the SDK, initialize it in this order:
- Call
NCEngine.initializewith your app's App Key. If you reinitialize with a different App Key, the client might clear session data for the current environment. The exact behavior depends on the API definition. - Call
NCCallEngine.initto initialize the Call engine and get anNCCallEngineinstance.
import { NCEngine } from '@nexconn/chat';
import { NCCallEngine } from '@nexconn/call';
NCEngine.initialize({
appkey: '<Your-Appkey>',
});
const ncCallEngine = NCCallEngine.init({});
The optional parameter type for NCCallEngine.init is INCCallInitOptions. Optional fields include isPubLowResolutionStream. For details, see the API documentation.
Initialize with CDN
NCEngine.initialize({
appkey: '<Your-Appkey>',
});
const ncCallEngine = NCCallEngine.init({});
Step 4: Get a user token
A token is mapped to a user ID and uniquely identifies an app user in Nexconn. Before a client can use Nexconn services, it must connect to Nexconn IM and provide a token.
For evaluation and debugging, use the Get Token API in the Console's API debugging page to get an access token for the user whose userId is 1. After you submit the request, copy the token string from the response body.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"code": 200,
"userId": "1",
"token": "gxld6GHx3t1eDxof1qtxxYrQcjkbhl1V@sgyu.cn.example.com;sgyu.cn.example.com"
}
Nexconn client SDKs do not provide an API for getting tokens. In production, call the Nexconn Server API to register a user and obtain an access token. For details, see the Server API documentation for Register user.
Step 5: Connect to Nexconn
Before you can place or answer a 1-to-1 call or start a group call, you must connect to Nexconn and authenticate with the user token.
After you get the token, call NCEngine.connect and check isOk in the result:
const result = await NCEngine.connect({
token: '<Your-Token>',
});
if (result.isOk) {
console.log('connect success');
} else {
console.log('connect failed');
}
Step 6: Add event handlers
Call SDK provides INCCallEventsListener for handling call-related events. For example, you can answer or hang up when an incoming call arrives, accept or reject a media type upgrade request, or display the call duration after the call start time is available.
Use setCallEventsListener on the NCCallEngine instance to register the listener:
// Register app-level call event handlers.
ncCallEngine.setCallEventsListener({
/**
* Incoming call notification.
* When a call comes in, you can answer or hang up.
* @param session Current call session
* @param extra Extra data passed by the caller when the call was started
*/
async onCallReceived(session: NCCallSession, extra?: string) {
const callId = session.getCallId();
console.log(`Incoming call, callId: ${callId}`);
const { code } = await ncCallEngine.acceptCall(callId);
console.log(`Accept call result, code: ${code}`);
},
/**
* Audio or video for a specific user is ready to play.
* Call playMedia(userId, mediaType) to start playback.
* Always check both the user ID and the media type. Do not play
* locally captured audio on the same device, or you might cause echo or feedback.
*
* @param userId User ID
* @param mediaType Media type
*/
onUserMediaAvailable(userId: string, mediaType: NCCallMediaType) {
ncCallEngine.playMedia(userId, mediaType);
},
/**
* Participant state changed.
* @param callId Call ID
* @param userId User whose state changed
* @param state New state
* @param reason Reason for the change
*/
onRemoteUserStateChanged(
callId: string,
userId: string,
state: NCCallUserState,
reason?: NCCallEndReason,
) {
console.log(`Participant state changed, callId: ${callId}, ${userId}: ${NCCallUserState[state]}, reason: ${reason}`);
},
/**
* Call ended. In a group call, a local hang-up does not always
* mean the entire call has ended.
* @param session Current call session
* @param reason End reason
*/
onCallEnded(session: NCCallSession, reason: NCCallEndReason) {
console.log(`Call ended, callId: ${session.getCallId()}, reason: ${reason}`);
}
});
If you do not register INCCallEventsListener, the user cannot receive incoming call events such as onCallReceived. Register the listener as soon as possible after NCCallEngine.init returns.
Step 7: Add video elements for media playback
A video playback element is an HTMLVideoElement <video> that displays a video stream. To show local and remote video, add these two elements to your page. The video element with the ID local_video_element_id is used for the local stream, and the element with the ID remote_video_element_id is used for the remote stream. Audio playback uses an internal Audio object created by the SDK, so you do not need to manage it yourself.
<video id="local_video_element_id"></video>
<video id="remote_video_element_id"></video>
After the page contains these two elements, call ncCallEngine.setVideoView to bind video views for the users you want to watch. After you bind a video element for user A, the SDK notifies your app through onUserMediaAvailable when A's video becomes available. You can then call ncCallEngine.playMedia() to play the media.
/**
* Set media players for the users you want to watch, including the local user and remote users.
* @param list A list of media player bindings
* @param item.userId User ID
* @param item.videoElement A video element mounted in your page
* @param item.useTinyStream Whether to subscribe to the remote user's low-resolution stream
* @returns code Whether the call succeeded
*/
setVideoView(list: { userId: string; videoElement: HTMLVideoElement; useTinyStream?: boolean }[]): { code: number }
Set the local and remote video views before placing or answering a call:
ncCallEngine.setVideoView([
{
userId: '<local-userId>',
videoElement: document.getElementById('local_video_element_id') as HTMLVideoElement,
},
{
userId: '<remote-userId>',
videoElement: document.getElementById('remote_video_element_id') as HTMLVideoElement,
},
]);
You must set the local video view before placing or answering a call. You can set the remote user's video view in advance, or only after the remote user reaches NCCallUserState.ONCALL in the onRemoteUserStateChanged callback. If you want the remote low-resolution stream, set useTinyStream to true.
Make a 1-to-1 call
Call SDK for Web supports 1-to-1 calls through NCCallType.SINGLE and group calls through NCCallType.MULTI. This section uses a 1-to-1 call as the example. For a 1-to-1 call, pass only one callee user ID. The call is created only after the callee answers.
Step 8: Start a call
The startCall method accepts optional pushConfig and extra parameters. pushConfig carries mobile push settings through INCCallPushConfig, including pushTitle, pushContent, and platform-specific push attributes. extra carries custom data that is passed through to the callee.
You can now call startCall with the target user ID to place your first audio or video call. After the call starts successfully, the SDK returns a callId.
After startCall succeeds, the callee receives the call in the onCallReceived listener that you added in step 6. The callee can then complete step 9 to establish the call.
/**
* Start a call.
* @param calleeIds Callee user ID. For a one-to-one call, you can pass a single string.
* @param callType Call type: single or multi-party
* @param mediaType Call media type: audio or video
* @returns callId Session ID created after the call starts successfully
*/
const { code, callId } = await ncCallEngine.startCall(
'<userId>',
NCCallType.SINGLE,
NCCallMediaType.VIDEO,
);
Step 9: Answer the call
After the callee receives an incoming call through onCallReceived in INCCallEventsListener, the app can call acceptCall on the NCCallEngine instance:
/**
* Incoming call notification.
* When a call comes in, you can answer or hang up.
* @param session Current call session
* @param extra Extra data passed by the caller when the call was started
*/
async onCallReceived(session: NCCallSession, extra?: string) {
const callId = session.getCallId();
const { code } = await ncCallEngine.acceptCall(callId);
console.log(`Accept call result, code: ${code}`);
}
After the call is answered successfully, Call SDK establishes the media session automatically.
Start a group call
Call SDK for Web supports group calling through NCCallType.MULTI. Starting a group call uses the same method as a 1-to-1 call, but you must set the call type to NCCallType.MULTI. Billing starts as soon as the group call is created successfully.
You can invite more users during a 1-to-1 call. After the invitation succeeds, the call type changes to a group call automatically. For details, see group calls.
Step 10: Place a group call
When you call ncCallEngine.startCall for a group call, pass the remote user IDs and the media type, and set the call type to NCCallType.MULTI. A video call supports up to 16 participants. An audio call supports up to 32 participants.
/**
* Start a call.
* @param calleeIds Callee user ID list
* @param callType Call type: single or multi-party
* @param mediaType Call media type: audio or video
* @returns callId Session ID created after the call starts successfully
*/
const { code, callId } = await ncCallEngine.startCall(
['<userId1>', '<userId2>'],
NCCallType.MULTI,
NCCallMediaType.VIDEO,
);
The answer flow for a group call is the same as for a 1-to-1 call.
For full implementation guidance, see the 1-to-1 call and group call documents. Build the complete 1-to-1 flow first, then add the steps that are specific to group calls.