Joining & Creating Calls

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

Call

Call represents the main building block of our SDK. This object abstracts away the user actions, join flows and exposes the call state.

Create call

You can create a call by specifying its callType and callId:

The Call Type controls which features are enabled, and sets up permissions. You can reuse the same call multiple times. As an example, if you’re building a telemedicine app calls will be connected to an appointment. Using your own appointment id as the call id makes it easy to find the call later.

const callType = "default";
const callId = "test-call";

const call = client.call(callType, callId);
await call.getOrCreate();

// or create it with options:
await call.getOrCreate({
  data: {
    /* call creation options */
  },
});

See all possible options at the Call creation options section.

Join call

const callType = "default";
const callId = "test-call";

const call = client.call(callType, callId);
await call.join();

Create and join a call

For convenience, you can create and join a call in a single operation. One of the flags you can provide there is create. Set this to true if you want to enable creating new call. Set it to false if you only want to join an existing call.

See all possible options at the Call creation options section.

await call.join({
  create: true,
  data: {
    /* call creation options */
  },
});

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 a special permission (OwnCapability.JOIN_ENDED_CALL) can join an ended call.

Load call

Existing calls can be loaded through the following API:

const call = client.call(type, id);
await call.get(); // just load

await call.getOrCreate(); // create if not present and load it

These operations initialize the call.state and create a subscription for call updates to our backend. This means that this call instance will receive real-time updates in case it is modified somewhere else.

Read more about call state here: Call & Participant State.

Update call

After creating a call, you can update some of its properties:

import { RecordSettingsRequestModeEnum } from "@stream-io/video-client";

await call.update({
  custom: { color: "green" },
  settings_override: {
    recording: {
      mode: RecordSettingsRequestModeEnum.DISABLED,
    },
  },
});

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
notifyIf you want the call to nofiy each member by sending push notification.false

Set call members

const call = client.call(type, id);
await call.getOrCreate({
  data: {
    members: [{ user_id: "alice", role: "admin" }, { user_id: "bob" }],
  },
});

Update call members

await call.updateCallMembers({
  update_members: [{ user_id: "charlie", role: "admin" }],
  remove_members: ["alice"],
});

Custom call data

await call.getOrCreate({
  data: {
    custom: { color: "blue" },
  },
});

Settings override

By default, the call instances inherit the settings defined in the call type. In some cases, you might want to override call settings on the instance itself:

// at creation time
await call.getOrCreate({
  data: {
    settings_override: {
      audio: { mic_default_on: false },
      video: { camera_default_on: false },
    },
  },
});

// or later
await call.update({
  settings_override: {
    video: { camera_default_on: true },
  },
});

Backstage setup

The backstage feature makes it easy to build a use-case where you and your co-hosts can set up your camera before going live. Only after you call call.goLive() the regular users will be allowed to join the livestream.

However, you can also specify a join_ahead_time_seconds, which will allow regular users to join the livestream before the call is live, in the specified join time before the stream starts.

Here’s an example of how to do that:

await call.getOrCreate({
  data: {
    starts_at: new Date(Date.now() + 500 * 1000), // 500 seconds from now
    settings_override: {
      backstage: {
        enabled: true,
        join_ahead_time_seconds: 300,
      },
    },
  },
});

In the code snippet above, we are creating a call that starts 500 seconds from now. We are also enabling backstage mode, with a join_ahead_time_seconds of 300 seconds. That means that regular users will be able to join the call 200 seconds from now.

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"],
});
© Getstream.io, Inc. All Rights Reserved.