Skip to main content

Room and Events

Telnyx's video JavaScript SDK lets you manage room events and join/leave notifications.

We've made it much easier to add video capability to your web application using our Javascript SDK.

The Room object and the Events that occur in a Room is the API you will use to build your video application. We've extensively documented the interface for the Room and Events objects, below.

Room

export type Room = Immutable<{
/// The unique identifier of the Room instance
id: string;

/// Event listener/handler for various events that are triggered in the room.
/// See the Events interface for a list.
on<E extends keyof Events>(event: E, callback: Events[E]): Unsubscribe;

/// Connects a Room instance to the server
/// The state of the room, specifically the status of the room, will change while it's connecting,
/// if you can listen to these changes with the state_changed event.
/// Once the room is connected its local partipant will available in State.
connect: () => Promise<void>;

/// Disconnect a Room instance from the server
/// The status of the state of the room will change while it's disconnecting.
disconnect: () => Promise<void>;

/// Updates the client token
/// The client token is a short lived access token that expires after a time to live in seconds,
/// which needs to be refreshed using a refresh token.
/// If you are farmilar with how JWT's work you'll understand, head here for [more details](https://jwt.io)
/// This was set when the client token was created - the default TTL is 600 seconds or 10 minutes.
///
/// Client tokens need to refreshed before they expire otherise the Room instance will automatically
/// disconnect.
/// It's up to the developer to keep the client token fresh.
/// To create a client token please use the `generate_join_client_token` endpoint
/// To refresh a token please use `refresh_client_token` endpoint
updateClientToken: (clientToken: string) => Promise<void>;

/// Gets the state of the Room
/// What does the state of the room look like?
/*
type Status =
| 'initialized'
| 'connecting'
| 'connected'
| 'disconnecting'
| 'disconnected';

interface State {
status: Status;
localParticipantId: Participant['id'];
participants: {
[id: string]: Participant;
};
streams: {
[id: string]: Stream;
};
}
*/

/// State is important because there can be lot of things changing in a room at any given moment, especially for really large rooms.
/// Participants leaving the room, new participants joining, other starting/stopping their video, a moderator kicking
/// a participant out.
/// It would be a lot to keep track of manually, which is why we have state.
/// Don't worry we've abstracted all the accounting, inside our SDK, and provided you with helper methods
/// like this one, getParticipant(), and getLocalStreams() to make access simple.
getState: () => State;


/// Participants and Streams
/// There's a two entities that are important to understand
/// and as you can see from the State interface above they are big
/// part of the State of the Room.
///
/// Stream
/// A stream represents media stream published by Participant in a Room.
/// It's identified by it's participantId and streamKey and typically has a audio track or a video
/// track, or both.


/// Participants
/// There are two type of participants: local and remote.
/// Remote Participant - other participants in the room who are not the local participant.
/// A local partipant subscribes to streams published by remote participants.
///
/// Local Participant - is the person on a mobile device or desktop that joins the room to publish a stream.
/// **NOTE**: There can only be one local participant in a room at a given time.


/// Gets the local participant for a given Room instance
/// You can use this method to find more details about the local participant in the Room
///
/// What does a Participant look like?
/*
export type Participant = Immutable<{
id: string;
context?: string;
streams: {
[key: string]: Stream['id'];
};
canReceiveMessages: boolean;
origin: 'local' | 'remote' | 'telephony_engine';
}>;
*/
getLocalParticipant: () => Participant;


/// Get the streams associated to the local participant
getLocalStreams: () => { [key: Stream['key']]: Stream };

/// Add a stream to a Room
/// key - is the unique identifier for the stream based on its realted participant.
/// tracks.audio - the audio track
/// tracks.video - the video track
/// Once the promise is completed you can assume that the stream has started publishing in the room.
addStream: (
key: Stream['key'],
tracks?: {
audio?: MediaStreamTrack;
video?:
| MediaStreamTrack
| { track?: MediaStreamTrack; options?: { enableSimulcast?: boolean } };
}
) => Promise<void>;

/// Update an existing stream in a Room
/// key - identifier of the stream
/// tracks.audio - the audio track
/// tracks.video - the video track
///
/// Why would you update a Stream?
/// If you wanted to mute the audio of a particular stream you would update
/// it and set the track to null
updateStream: (
key: Stream['key'],
tracks?: {
audio?: MediaStreamTrack;
video?:
| MediaStreamTrack
| { track?: MediaStreamTrack; options?: { enableSimulcast?: boolean } };
}
) => Promise<void>;

/// Remove a stream
/// key - identifier of the stream
/// Removing a stream removes or unpublishes it from the room.
removeStream: (key: string) => Promise<void>;


/// Subscriptions
/// A subscription is used to subscribed to a stream published by a Remote Participant


/// Subscribe to a stream belonging to a remote participant
/// participantId - the id of the remote participant
/// key - the stream key of the stream
/// config.audio - flag to indicate if you'd like to subscribe to the remote streams' audio
// config.video - flag to indicate if you'd like to subscribe to the remote streams' video
/// When the promise is fullfilled a remote stream is added to state.streams
/// which then can be used to render the audio or video of that stream.
/// You can access remote participant streams more easily using the getParticipantsStreams
// and getParticipantStreams helper methods below.
///
/// A developer is not required to subscribe to every remote stream being published in the room instead
/// they can choose. This is very useful in situations conserving bandwidth and cpu resources is a priority,
/// For example:
/// A developer building a vidoe conferencing application and wants to support 100+ participants may only want subscribe
/// to 15-20 participants at a time display each set in a seperate page, thus significantly saving bandwith and resources.
addSubscription: (
participantId: Participant['id'],
key: Stream['key'],
config: { audio: boolean; video: boolean }
) => Promise<void>;


/// Update an existing subscription
/// participantId - the id of the remote participant
/// key - the stream key of the stream
/// config.audio - flag to indicate if you'd like to subscribe to the remote streams' audio
// config.video - flag to indicate if you'd like to subscribe to the remote streams' video
/// When a remote participant toggles audio or video on a stream that you're subscribed to
/// you'll need to update that subscription.
updateSubscription: (
participantId: Participant['id'],
key: Stream['key'],
config: { audio: boolean; video: boolean }
) => Promise<void>;

/// Remove or stop subscribing to a remote participant's stream
removeSubscription: (
participantId: Participant['id'],
key: Stream['key']
) => Promise<void>;

/// Helper method to easily access all streams for a given remote participant
getParticipantStreams: (
participantId: Participant['id']
) => Map<Stream['key'], Stream>;

/// Helper method to easily access a remote participant stream
getParticipantStream: (
participantId: Participant['id'],
key: Stream['key']
) => Stream | undefined;

/// Provides statistics for a local or remote stream
/// It presents the same data you'd get from doing:
/// RTCRtpSender.getStats() - https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/getStats
/// RTCRtpReceiver.getStats() - https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpReceiver/getStats
/// using the standard WebRTC APIs but in a much more readable format.
getWebRTCStatsForStream: (
participantId: Participant['id'],
key: Stream['key']
) => Promise<WebRTCStats>;

/// Send a message to one, more than one, or all participants in the room
/// message - a message type, current only 'text' is supported
/// receipients? - an array of participants to send the message, if
/// null the message is broadcasted to everyone in the room.
sendMessage: (
message: Message,
recipients?: Array<Participant['id']>
) => Promise<void>;


enableNetworkMetricsReport: (
participantIds: Array<Participant['id']>,
options?: { includeStreams?: boolean }
) => Promise<void>;

disableNetworkMetricsReport: (
participantIds?: Array<Participant['id']>
) => Promise<void>;
}>;

Room events

export interface Events {
/// Triggered when the state of the room changes
/// For more
/// TODO
state_changed: (state: State) => void;

/// Triggers on a Room instance when it connects to the server
connected: (state: State) => void;

/// Triggers on a Room instance when it disconnects from the server
disconnected: (state: State) => void;

/// Triggered when a remote participant joins the room
/// Only triggered for remote participants the local participant does not
/// need to be notified that they've joined the room since they've initiated
/// that action themselves by connecting to the Room
participant_joined: (participant: Participant['id'], state: State) => void;


/// Triggered when a participant is leaving the room because they were kicked
/// due to a moderator event
/// Unlike the joined and left events the local participant can be kicked from the room
participant_leaving: (
participant: Participant['id'],
reason: 'kicked' | null,
state: State
) => void;

/// Triggered when a remote participant leaves the room
participant_left: (participantId: Participant['id'], state: State) => void;

/// Triggered after successfully adding or publishing a stream to the room
/// This event is triggered for local and remote streams.
/// A local stream is one that's published by the local participant in the Room
/// A remote stream is one that's published by a remote participant in the Room
stream_published: (
participantId: Participant['id'],
key: Stream['key'],
state: State
) => void;

/// Triggered after successfully unregistering a stream
/// This event is triggered for both local and remote streams.
/// It triggered when the local or remote participant remove or stops publishing a stream.
/// When a remote participant leaves a room it will trigger for any of their related streams.
stream_unpublished: (
participantId: Participant['id'],
key: Stream['key'],
state: State
) => void;

/// Triggered when a local stream or a remote stream track has been enabled.
/// Notifies consumers about remote stream tracks being enabled.
/// For example: when audio is unmuted or video has started on a remote stream.
track_enabled: (
participantId: Participant['id'],
key: Stream['key'],
kind: 'audio' | 'video',
state: State
) => void;

/// The oposite of track_enabled
/// Triggers when a local stream or a remote stream track has been disabled.
/// Notifies consumers about remote stream tracks being disabled.
/// For example: when audio is muted or video has stopped on a remote stream.
track_disabled: (
participantId: Participant['id'],
key: Stream['key'],
kind: 'audio' | 'video',
state: State
) => void;

/// Triggered when a track is censored due to a moderator event
/// Like the kick moderator event in participant_leaving, both local and remote streams can be
/// censored.
///
/// Since a Stream consists of an audio and video track, either can be censored by a moderator
/// If the audio or video track on given stream is null, effectively nothing happens.
track_censored: (
participantId: Participant['id'],
key: Stream['key'],
kind: 'audio' | 'video',
state: State
) => void;

/// Triggered when a track is uncensored due to a moderator event
/// Opposite of track_censored
/// Naturally, a track must be censored to order be uncensored.
track_uncensored: (
participantId: Participant['id'],
key: Stream['key'],
kind: 'audio' | 'video',
state: State
) => void;

/// Triggered when there is audio activity from a particular stream or participant talking in the Room
/// When there's audio activity when a participant speaking this event will trigger with the participant id that's talking and the stream key will be null
audio_activity: (
participantId: Participant['id'],
key: Stream['key'] | null,
state: State
) => void;

/// Triggered a subscription to a remote stream is started
subscription_started: (
participantId: Participant['id'],
key: Stream['key'],
state: State
) => void;

/// Triggered when the subscription is reconfigured using the updateSubscription method
subscription_reconfigured: (
participantId: Participant['id'],
key: Stream['key'],
state: State
) => void;

/// Triggered when subscription is removed or ended for a remote stream
/// A subscription can be ended by calling `removeSubscription(ParticipantId,StreamKey)`
/// This is also triggered when a remote participant leaves the room.
subscription_ended: (
participantId: Participant['id'],
key: Stream['key'],
state: State
) => void;

/// onMessageReceived
/// Triggered when a new message is recieved either by one or more participants or broadcasted to all participants
/// in the room.
/// participantId - sender of the message
/// recipients - an array of participants the message was sent to. when null the message was broadcasted to the all participants in the room.
message_received: (
participantId: Participant['id'], // the participant that sent the message
message: Message,
recipients: Array<Participant['id']> | null,
state: State
) => void;

network_metrics_report: (networkMetrics: NetworkMetrics) => void;
}