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.
Sign up at https://console.agora.io 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 https://docs.agora.io/en/Video/token?platform=All%20Platforms.
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.
This is the structure of the application that we are building:
.
├── android
├── components
│ └── Permission.ts
│ └── Style.ts
├── ios
├── App.tsx
.
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 IDtoken
: token generated to join the channelinCall
: boolean to store if we’re in an active video chat roominLobby
: boolean to store if we’re in the lobbyinput
: string to store input when creating a new roompeerIdsRTC
: array to store the RTC UIDs of other users in the video chat roomseniors
: array storing RTM members who have joined the video chat room before usmyUsername
: local user’s name to log in to RTMrooms
: dictionary to store room names and their member countWe 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.
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.
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 }
).
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.
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.
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.
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.