const { participants$ } = call.state;
const subscription = participants$.subscribe((participants) => {
console.log(participants);
});
// dispose the subscription when you don't need it anymore
subscription.unsubscribe();
Call & Participant State
The call, participant and client states are reactive. Their value is updated on WebSocket events and API calls. We use the RxJS library for this, each state property is an Observable.
Let’s see an example, this is how you can subscribe to changes related to participants:
The console.log
method will be called each time there is a change to the list of participants in the call.
This approach makes it possible to access the state and be notified about changes anywhere in your application without having to manually subscribe to WebSocket events.
Alternatively, you can also access the current value of each state variable:
const { participants } = call.state;
console.log(participants);
It’s useful when you need to know the current value, but you don’t need to be notified about future changes.
Call state
The call state can be accessed through call.state
object as in the examples above.
In this object, you’ll find properties that are reactive and static as well.
The reactive/observable properties are suffixed with $
and the static ones are without the suffix.
For the best experience, please make sure that the call
instance is loaded
and connected to our backend: Load Call.
Otherwise, call.state
observables will emit empty values and you won’t get real time updates.
Here is an excerpt of the call state properties:
Reactive value | Static value | Description |
---|---|---|
backstage$ | backstage | true when the call runs in backstage mode |
blockedUserIds$ | blockedUserIds | The list of blocked user IDs. |
callingState$ | callingState | Provides information about the call state. For example, RINGING , JOINED or RECONNECTING . |
callStatsReport$ | callStatsReport | When stats gathering is enabled, this observable will emit a new value at a regular (configurable) interval. |
createdAt$ | createdAt | The time the call was created. |
createdBy$ | createdBy | The user who created the call. |
custom$ | custom | Custom data attached to the call. |
dominantSpeaker$ | dominantSpeaker | The participant that is the current dominant speaker of the call. |
egress$ | egress | The egress data of the call (for broadcasting and livestreaming). |
endedAt$ | endedAt | The time the call was ended. |
endedBy$ | endedBy | The user who ended the call. |
hasOngoingScreenShare$ | hasOngoingScreenShare | It will return true if at least one participant is sharing their screen. |
ingress$ | ingress | The ingress data of the call (for broadcasting and livestreaming). |
members$ | members | The list of call members |
ownCapabilities$ | ownCapabilities | The capabilities of the local participant. |
pinnedParticipants$ | pinnedParticipants | The participants that are currently pinned. |
recording$ | recording | The recording state of the call. |
session$ | session | The data for the current call session. |
settings$ | settings | The settings of the call. |
startedAt$ | startedAt | The actual start time of the current call session. |
startsAt$ | startsAt | The time the call is scheduled to start. |
thumbnails$ | thumbnails | The thumbnails of the call. |
transcribing$ | transcribing | The transcribing state of the call. |
updatedAt$ | updatedAt | The time the call was updated. |
Your IDE of choice may help you to discover the other properties of the call state.
Participant state
If you want to display information about the joined participants of the call you can use the following properties in call.state
:
Reactive value | Static value | Description |
---|---|---|
localParticipant$ | localParticipant | The local participant is the logged-in user. |
remoteParticipants$ | remoteParticipants | All participants except the local participant. |
participants$ | participants | All participants, including local and remote participants. |
participantCount$ | participantCount | The approximate participant count of the active call. This includes the anonymous users as well, it is computed on the server-side. |
anonymousParticipantCount$ | anonymousParticipantCount | The approximate participant count of anonymous users in the active call. |
The StreamVideoParticipant
object contains the following information:
Name | Description |
---|---|
audioLevel | The audio level of the participant (determined on the server). |
audioStream | The published audio MediaStream . |
audioVolume | The audio volume level of the participant (overridable local audioVolume level). |
connectionQuality | The participant’s connection quality. |
custom | The participant’s custom data. Comes from the custom field of the user object. |
image | The image of the participant. |
isDominantSpeaker | It’s true if the participant is the current dominant speaker in the call. |
isLocalParticipant | It’s true if the participant is the local participant. |
isSpeaking | It’s true if the participant is currently speaking. |
joinedAt | The time the participant joined the call. |
name | The name of the participant. |
pin | Holds pinning information. |
publishedTracks | The track types the participant is currently publishing |
reaction | The last reaction this user has sent to this call. |
roles | The roles of the participant in this call. |
sessionId | The identifier of the participant within the existing call session |
screenShareAudioStream | The published screen share audio MediaStream . |
screenShareStream | The published screen share MediaStream . |
userId | The user ID of the participant. |
videoStream | The published video MediaStream . |
viewportVisibilityState | The viewport visibility state of the participant. |
The SDK also provides a few utility functions that help you to work with participants:
import {
Call,
hasAudio,
hasScreenShare,
hasScreenShareAudio,
hasVideo,
isPinned,
} from "@stream-io/video-client";
let call: Call;
// example usage
const subscription = call.state.participants$.subscribe((participants) => {
for (let participant of participants) {
// check if the participant has audio, video, screen share or screen share audio
const hasAudioOn = hasAudio(participant);
const hasVideoOn = hasVideo(participant);
const hasScreenShareOn = hasScreenShare(participant);
const hasScreenShareAudioOn = hasScreenShareAudio(participant);
const isPinnedOn = isPinned(participant);
}
// participants with a specific role
const hosts = participants.filter((p) => p.roles.includes("host"));
// participants that publish video and audio
const videoParticipants = participants.filter(
(p) => hasVideo(p) && hasAudio(p),
);
});
subscription.unsubscribe();
In a call with many participants, the value of the participants$
call state observable is truncated to 250 participants. The participants who are publishing video, audio, or screen sharing have priority over the other participants in the list. This means, for example, that in a livestream with one host and many viewers, the host is guaranteed to be in the list.
Client state
The client state can be accessed by client.state
.
Here is the list of client state properties:
Reactive value | Static value | Description |
---|---|---|
connectedUser$ | connectedUser | Returns the connected user. Holds the server-side data of the connected user. |
calls$ | calls | A list of all tracked calls. These calls can be outgoing (I have called somebody) or incoming (somebody has called me). Loaded calls (call.get() ) are also part of this list. |
The connectedUser
object contains the following properties:
Name | Description |
---|---|
created_at | The time the user was created. |
custom | Custom user data. |
deleted_at | The time the user was deleted. |
devices | The registered push notification devices of the user. |
id | The id of the user. |
image | The profile image of the user. |
name | The name of the user. |
role | The role of the user. |
teams | The teams the user belongs to. |
updated_at | The time when the user was updated. |