DEV Community

Cover image for Dynamic Channels for Video Chat Using Agora RTM on React Native
Ekaansh Arora
Ekaansh Arora

Posted on • Originally published at

Dynamic Channels for Video Chat Using Agora RTM on React Native

The Agora RTC (Real-time Communication) SDK makes it easy to build video chat apps on React Native. We can have multiple users communicate with each other by using the same channel name for our video chat room.

If you’re building a social video chat app, you might want to let your users generate rooms that other users can browse, join, and communicate in. You can do this with a back-end server to handle these requests and update other users with information about created rooms, but that would involve writing back-end code and hosting your own server.

In this tutorial, we’re going to see an alternative way of achieving the same goal by using the Agora RTM (Real-time Messaging) SDK. We’ll use messages sent by users to communicate the creation and updating of dynamic video chat rooms, all with front-end code.

This can be handy because when you don’t want to build a back-end server, you can use messages to update other users on the status of the rooms. This approach can be easily extended to having fully managed rooms as well as features like admin admit/deny a user, mute another user, and remove a user from the room.

We’ll be using the Agora RTC SDK and Agora RTM SDK for React Native in this example. I’m using v3.2.2 of the RTC SDK and v1.2.2-alpha.3 of the RTM SDK at the time of writing.

Project Overview

  • We have an RTM room called ‘lobby’. We’ll use it to signal users when someone creates a new room or when the members in a room change.
  • The way we’ll do this is by having the most senior member in the video chat room send messages to others. The oldest member in the room is considered the senior member, more on this later.
  • We’ll send messages in the form of ‘roomName:memberCount’ which can be processed by other users to store the room name and member count as a dictionary in their application state. We’ll use it to render a list of rooms with the number of members in it.
  • Once we have the list, we can join the room by using the RTC SDK. We’ll also need to listen for users joining and leaving to update the member count for everyone else. This is done only by the senior member to avoid overhead.
  • We also need to consider two cases to update room information for other users. First, when a new user joins the lobby, the senior-most member in each channel sends the user a peer message. Second, when a channel’s member count is updated we send a channel message to all users connected to the lobby to update their room list.

Creating an Agora account

Sign up for an account and log in to the dashboard.

Navigate to the Project List tab under the Project Management tab, and create a project by clicking the blue Create button. (When prompted to use App ID + Certificate, select only App ID.) The App ID will be used to authorize your requests while you’re developing the application, without generating tokens. Copy the App ID someplace safe, we’ll need it in a bit.

Note: This guide does not implement token authentication, which is recommended for all RTE apps running in production environments. For more information about token-based authentication in the Agora platform, see

Download the Source

You can jump to the code if you like. The code is open source and available on GitHub. To try it out for yourself, see the readme for steps on how to run the app.

Screenshots from the app running on an Android Emulator

Structure of our example

This is the structure of the application that we are building:

├── android  
├── components  
│ └── **Permission.ts**  
│ └── **Style.ts**  
├── ios  
├── **App.tsx  
Enter fullscreen mode Exit fullscreen mode


App.tsx will be the entry point into the app. We’ll have all our code in this file.

We start by writing the import statements. Next, we define an interface for our application state containing the following:

  • **appId**: our Agora App ID
  • **token**: token generated to join the channel
  • **inCall**: boolean to store if we’re in an active video chat room
  • **inLobby**: boolean to store if we’re in the lobby
  • **input**: string to store input when creating a new room
  • **peerIdsRTC**: array to store the RTC UIDs of other users in the video chat room
  • **seniors**: array storing RTM members who have joined the video chat room before us
  • **myUsername**: local user’s name to log in to RTM
  • **rooms**: dictionary to store room names and their member count

We define a class-based component: the _rtcEngine variable will store the instance of the RtcEngine class, and the _rtmEngine variable will store the instance of the RtmEngine class, which we can use to access the SDK functions.

In the constructor, we set our state variables and request permission for recording audio on Android. (We use a helper function from permission.ts as described below.) When the component is mounted, we call the initRTC and initRTM functions, which initialize the RTC and RTM engines using the App ID. When the component unmounts, we destroy our engine instances.

RTC Initialization

We use the App ID to create our engine instance. We use the enableVideo method to set the SDK in video mode.

The RTC triggers a userJoined event for each user present when we join the channel and for each new user who joins later. The userOffline event is triggered when a user leaves the channel. We use event listeners to keep our peerIds array updated with UIDs. We will use this array later to render the video feeds from other users.

Once we’ve joined a channel, the SDK triggers the JoinChannelSuccess event. We set our state variable inCall as true to render the video chat UI.

When a new user joins our video chat room, if we’re the senior member as discussed before, we send a channel message with the updated user count to all members across channels using the lobby RTM channel.

RTM Initialization

We’re using RTM to send our room name and member count. We maintain an array of seniors, that is, members who have joined the call before us. If the seniors array size is <2, it means we’re the senior-most member, responsible for the signaling. (The local user is also part of the array.)

First, we attach the channelMemberJoined and channelMemberLeft listeners, which are triggered when a user joins or leaves the RTM channel. When a user joins the lobby channel, if we’re the senior-most member we send them a peer message. If a user leaves the current video chat channel, we update the seniors array (removing them from it if they had arrived before us). We also send a channel message to the lobby if we are the senior member updating the count.

Next, we attach the channelMessageReceived and messageReceived event listeners, which are triggered when we receive a channel message and a peer message, respectively. We split the channelName:memberCount string (for example, ‘helloWorld:5’) and use the two pieces of data to update our dictionary. (for example, rooms: { ‘helloWorld’: 5, ‘roomTwo’: 3 }).

Join a Call

We define a function to join the call that takes in the channel name as an argument. We update the state with the channel name and join the channel on both RTM and RTC, using the joinChannel methods.

We use the getChannelMembersBychannelId method on RTM to get the UIDs of the users on the channel. If we’re the only member, we send a channel message to the lobby channel on RTM to update everyone about the created room.

Leaving the Call

We leave the RTM and RTC video chat room channels but stay connected to the lobby channel on RTM to keep receiving updates. We update our state by clearing the peerIds array, the seniors array, and the channelName. We also set inCall as false and inLobby as true to render the lobby UI.

Rendering Our UI

We define the render function for displaying buttons to display the status if we’re in a call or the lobby.

We use the _renderRooms function to render a scroll view, which iterates over the rooms dictionary to show a list of created rooms with their member count. The user can tap any room to join it, which calls the joinCall function. We also render a text input to let the user create a room that calls the same joinCall function with that input.

We use the _renderCall function to render the videos once we’re connected to a video chat room. We use the RtcLocalView component from the SDK to render our own (local user’s) video. We use RtcRemoteView inside a scroll view to render the videos of connected users using the UIDs stored in the peerIds array. We also display a button to leave the room.


We’re exporting a helper function to request microphone permissions from the Android OS.


The Style.ts file contains the styling for the components.

What’s next?

The same technique can be used to communicate other information, such as names of users connected, room description, and room title. We can even use the same mechanism to kick users off the call by sending an RTM message that, when evaluated, calls the leave channel method on the remote user’s device.


You’ve seen how we can leverage the Agora RTM SDK to share information and dynamically create video chat rooms. You can refer to the Agora React Native API Reference for methods that can help you quickly add more features to your next real-time engagement application.

Top comments (0)