Skip to main content

Joining and Creating Calls

With authentication out of the way, we can now focus on creating and joining calls. Before proceeding, we highly recommend that you read the previous section on authentication, as the two are closely related.

Creating Calls

To create a call, we first call the makeCall function on the StreamVideo class and pass it the call type and ID. The most common call type is default, which enables full audio and video transmission. However, as we will learn later, there are multiple call types (and even custom types) from which you can choose based on your use case.

final call = StreamVideo.instance.makeCall(callType: StreamCallType(), id: 'Your-call-ID');

Calling makeCall returns a Call object for us to work with. However, it does neither connect nor start transmitting data automatically. To create and join the call, we must then invoke getOrCreate on the returned object.

final call = StreamVideo.instance.makeCall(callType: StreamCallType(), id: 'Your-call-ID');
await call.getOrCreate(); // New

Although we are not passing any parameters to getOrCreate in the above example, it is important to note a few things:

  1. Members: Upon creation, we can supply a list of user IDs we would like to immediately add to the call.
  2. Ringing: If ringing is set to true, Stream will send a notification to the users on the call, triggering the platform call screen on iOS and Android.
note

Depending on call permissions settings, call member may have different permissions than other users joining the call. For example, call can be configured so only members can join. See here.

By default, calling getOrCreate assigns admin permission to each user who is supplied during creation.

When call is already active you can still manage members:

final call = client.makeCall(callType: StreamCallType(), id: 'my-call-id');
call.getOrCreate(memberIds: ['alice', 'bob']);

// grant access to more users
await call.updateCallMembers(updateMembers: [const UserInfo(id: 'charlie', role: 'call_member')]);
// or
await call.addMembers([const UserInfo(id: 'charlie', role: 'call_member')]);

// remove access from some users
await call.updateCallMembers(removeIds: ['charlie']);
// or
await call.removeMembers(['charlie']);

Call CRUD Operations

With calls, we make it easy to perform basic create, read, update, and delete (CRUD) operations on calls providing the user has sufficient permissions.

For example, once a call is created a user can call.update the information on the call by adding custom metadata such as a name, description, or any other arbitrary Map<String, Object> to the call before getOrCreate is invoked.

call.update(custom: {'name': 'My first Call'});
await call.getOrCreate();

Using the update method, a variety of settings can also be applied before the call is created such as:

  • Ring
  • Audio
  • Video
  • ScreenShare
  • Recording
  • Transcription
  • Backstage
  • Geofencing

Joining Calls

To join a call that already exists, you must first know two things:

  • The callType of the existing call
  • The ID of the existing call

Similar to the flow of creating a call, we can use makeCall to construct a Call class for us to perform operations on.

final call = StreamVideo.instance.makeCall(callType: StreamCallType(), id: 'My-existing-call-ID');

Next, with our class instantiated, we can connect to the call and SFU by invoking join.

await call.join();

Unlike the call creation flow and functions, the user must have sufficient permissions to join the call or a VideoError will be returned. All users connected via the join() function have the permission type of user by default and are limited in the actions they can perform.

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.

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

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

That's it. In just a few lines, we have created our first calls, and they are ready for the world to join. To learn how to observe events and the state of a call, please read the next chapter.

Did you find this page helpful?