Skip to main content

Joining & Creating Calls

This guide shows how to create, join, leave, and end call rooms and ring calls.

Call

Create and join a call

You create a call by specifying a call type and a call id.

const callType = 'default';
const callId = 'test-call';
await client.call(callType, callId).join({ create: true });

The call type controls which features are enabled, and sets up permissions.

One of the flags you can provide there is create. Set this to true if you want to enable creating new calls. Set it to false if you only want to allow joining existing calls.

See all possible options at the Call creation options section

If you don't want to join a call, just create one, you can use the getOrCreate method:

const callType = 'default';
const callId = 'test-call';
await client.call(callType, callId).getOrCreate();

See all possible options at the Call creation options section

Join with mic and camera on or off

You can override the default mic and camera settings before you join a call. Typically, you should configure this in your Lobby view:

const call = client.call('default', 'test-call');

// enable mic and camera
await call.camera.enable();
await call.microphone.enable();

// alternatively, you can disable them
await call.camera.disable();
await call.microphone.disable();

// and then join the call
await call.join();

Leave call

To leave a call, you can use the leave method:

await call.leave();

End call

Ending a call requires a special permission. This action terminates the call for everyone.

await call.endCall();

Only users with special permission can join an ended call.

Ring call

Create call

To create a ring call, we need to set the ring flag to true and provide the list of members we want to call. It is important to note that the caller should also be included in the list of members.

await client.call('default', 'test-outgoing-call').getOrCreate({
ring: true,
data: {
members: [
{ user_id: 'myself' },
{ user_id: 'my friend' },
],
},
});

See all possible options at the Call creation options section

This step will start the signaling flow. The caller will automatically join the call once the first callee accepts the call. The calling will automatically stop if all callee rejects the call.

Watch for incoming and outgoing calls

The easiest way to watch for incoming and outgoing calls is to use the useCalls hook.

import { useCalls, CallingState } from '@stream-io/video-react-sdk';

export const MyCallUI = () => {
const calls = useCalls();

// handle incoming ring calls
const incomingCalls = calls.filter(
(call) =>
call.isCreatedByMe === false &&
call.state.callingState === CallingState.RINGING,
);

const [incomingCall] = incomingCalls;
if (incomingCall) {
// render the incoming call UI
return <MyIncomingCallUI call={incomingCall} />;
}

// handle outgoing ring calls
const outgoingCalls = calls.filter(
(call) =>
call.isCreatedByMe === true &&
call.state.callingState === CallingState.RINGING,
);

const [outgoingCall] = outgoingCalls;
if (outgoingCall) {
// render the outgoing call UI
return <MyOutgoingCallUI call={outgoingCall} />;
}

return null;
};

You can also check the sample integration in the following CodeSandboxes:

Canceling a call

A caller can cancel an outgoing call until the first callee accepts the call. Canceling a call will stop the signaling flow.

await call.leave();

Please note that calling call.leave() after joining the call won't stop the signaling flow.

Accepting a call

A callee can accept or reject an incoming call. To accept and join the call:

await call.join();

Please note that it's possible to join multiple calls. If you only want to allow one active call, you must leave joined calls before accepting an incoming call.

Rejecting a call

A callee can accept or reject an incoming call. To reject the call:

await call.leave({ reject: true });

Leave call

To leave a joined call, you can use the leave method:

await call.leave();

End call

Ending a call requires a special permission. This action terminates the call for everyone.

await call.endCall();

Call creation options

The following options are supported when creating a call:

OptionDescriptionDefault
membersA list of members to add to this call. You can specify the role and custom data on these members-
customAny custom data you want to store-
settingsYou can overwrite certain call settings for this specific call. This overwrites the call type standard settings-
startsAtWhen the call will start. Used for calls scheduled in the future, livestreams, audio rooms etc-
teamRestrict the access to this call to a specific team-
ringIf you want the call to ring for each memberfalse

Restricting access

You can restrict access to a call by tweaking the Call Type permissions and roles. A typical use case is to restrict access to a call to a specific set of users -> call members.

Step 1: Set up the roles and permissions

On our dashboard, navigate to the Video & Audio -> Roles & Permissions section and select the appropriate role and scope. In this example, we will use my-call-type scope.

By default, all users unless specified otherwise, have the user role.

We start by removing the JoinCall permission from the user role for the my-call-type scope. It will prevent regular users from joining a call of this type.

Revoke JoinCall for user role

Next, let's ensure that the call_member role has the JoinCall permission for the my-call-type scope. It will allow users with the call_member role to join a call of this type.

Grant JoinCall for call_member role

Once this is set, we can proceed with setting up a call instance.

Step 2: Set up the call

const call = client.call('my-call-type', 'my-call-id');
await call.getOrCreate({
data: {
members: [
// please note the `role` property
{ user_id: 'alice', role: 'call_member' },
{ user_id: 'bob', role: 'call_member' },
],
},
});

// and if necessary, to grant access to more users
await call.updateCallMembers({
update_members: [{ user_id: 'charlie', role: 'call_member' }],
});

// or, to remove access from some users
await call.updateCallMembers({
remove_members: ['charlie'],
});

Did you find this page helpful?