Quickstart
Updated
Build a basic voice calling, video calling, or streaming app with the Agora RTC SDK.
This page provides a step-by-step guide on how to create a basic real-time app using the Agora RTC SDK. The same steps apply whether you're building voice calling, video calling, interactive live streaming, or broadcast streaming — only a few configuration values change based on your use case.
Understand the tech
To start a real-time session, implement the following steps in your app:
-
Initialize the engine: Before calling other APIs, create and initialize an engine instance.
-
Join a channel: Call methods to create and join a channel.
-
Join as a host: A live streaming event has one or more hosts. A host publishes audio and video to the channel and can also subscribe to streams from other hosts.
-
Join as audience: Audience members can only subscribe to streams published by hosts.
Note
For the voice calling and video calling use cases, each user joins as a host.
-
-
Send and receive audio and video: Hosts publish streams to the channel. Audience members subscribe to audio and video streams published by hosts.
-
For streaming applications, set the latency level based on your use case:
-
Interactive live streaming: Optimized for real-time interaction with ultra-low latency. Use this when hosts and audience need to interact quickly, such as in live Q&A sessions, interactive classrooms, or auctions.
-
Broadcast streaming: Optimized for scalability with slightly higher latency. Use this for large-scale events where one-way broadcasting is sufficient, such as concerts, sports events, or news broadcasts.
-
Prerequisites
- A camera and a microphone.
- A valid Agora account and project. See Agora account management for details.
- React Native 0.60 or later. See Get Started with React Native.
- Node.js 16 or later.
- Depending on your target platform:
- Android: a machine running macOS, Windows, or Linux; JDK 11 or later; the latest version of Android Studio; and a physical or virtual Android device running Android 5.0 or later.
- iOS: a machine running macOS; Xcode 10 or later; CocoaPods; and a physical or virtual iOS device running iOS 9.0 or later. If you use React Native 0.63 or later, ensure your iOS version is 10.0 or later.
Set up your project
Create a project
To create a new application using React Native Community CLI, see Get Started Without a Framework.
Install the SDK
Download and add the Agora RTC SDK to your React Native project. Choose either of the following methods:
In your project folder, execute the following command:
npm i --save react-native-agoraIn your project folder, execute the following commands:
# Install yarn
npm install -g yarn
# Use yarn to download Agora React Native SDK
yarn add react-native-agoraNote
React Native 0.60.0 and later support automatic linking of native modules. Manual linking is not recommended. See Autolinking for details
Implement Realtime Communication
This section guides you through the implementation of basic real-time audio and video interaction in your app.
The following figure illustrates the essential steps:
This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps and use the code in your App.tsx file.
Import dependencies
Add the required Agora dependencies to your app.
import {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
IRtcEngine,
RtcSurfaceView,
RtcConnection,
IRtcEngineEventHandler,
} from 'react-native-agora';Initialize the engine
For real-time communication, call createAgoraRtcEngine to create an RtcEngine instance, and then initialize the engine using RtcEngineContext to specify the App ID.
const appId = '<-- Insert app ID -->';
const setupVideoSDKEngine = async () => {
if (Platform.OS === 'android') { await getPermission(); }
agoraEngineRef.current = createAgoraRtcEngine();
const agoraEngine = agoraEngineRef.current;
await agoraEngine.initialize({ appId: appId });
};Join a channel
To join a channel, call joinChannel with the following parameters:
-
Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.
-
Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.
-
User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to
0when joining a channel, the SDK generates a random number for the user ID and returns the value in theonJoinChannelSuccesscallback. -
Channel media options: Configure
ChannelMediaOptionsto define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.
Set the channelProfile, clientRoleType, and audienceLatencyLevel according to your use case:
| Use case | Channel profile | Client role | Latency level |
|---|---|---|---|
| Voice calling | ChannelProfileCommunication | ClientRoleBroadcaster | N/A |
| Video calling | ChannelProfileCommunication | ClientRoleBroadcaster | N/A |
| Interactive live streaming | ChannelProfileLiveBroadcasting | ClientRoleBroadcaster or ClientRoleAudience | AudienceLatencyLevelUltraLowLatency (default) |
| Broadcast streaming | ChannelProfileLiveBroadcasting | ClientRoleBroadcaster or ClientRoleAudience | AudienceLatencyLevelLowLatency |
Note
- Only broadcasters can publish media. Audience members cannot publish until promoted to broadcaster.
- Choose Communication mode for calls where every user publishes, typically fewer than 17 participants. Choose Live Broadcasting mode for larger events with separate hosts and audience.
- The latency level only applies to the audience role, and affects your pricing tier.
The following example shows the configuration for interactive live streaming with separate host and audience roles:
const token = '<-- Insert token -->';
const channelName = '<-- Insert channel name -->';
const localUid = 0; // Local user UID, no need to modify
// Define the join method called after clicking the join channel button
const join = async () => {
if (isJoined) {
return;
}
if (isHost) {
// Join the channel as a broadcaster
agoraEngineRef.current?.joinChannel(token, channelName, localUid, {
// Set the channel profile according to your use case (see table above)
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// Set user role to broadcaster
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// Publish audio collected by the microphone
publishMicrophoneTrack: true,
// Publish video collected by the camera
publishCameraTrack: true,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
// Automatically subscribe to all video streams
autoSubscribeVideo: true,
});
} else {
// Join the channel as an audience
agoraEngineRef.current?.joinChannel(token, channelName, localUid, {
// Set the channel profile according to your use case (see table above)
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// Set user role to audience
clientRoleType: ClientRoleType.ClientRoleAudience,
// Only takes effect for the audience role
audienceLatencyLevel: AudienceLatencyLevelType.AudienceLatencyLevelLowLatency,
// Do not publish audio collected by the microphone
publishMicrophoneTrack: false,
// Do not publish video collected by the camera
publishCameraTrack: false,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
// Automatically subscribe to all video streams
autoSubscribeVideo: true,
});
}
};Note
Since the engine runs locally, reloading the app using the Metro bundler may cause the engine reference to be lost, preventing channel joining. To resolve this issue, restart the app.
Subscribe to RTC SDK events
The RTC SDK provides an interface for subscribing to channel events. To use it, create an instance of IRtcEngineEventHandler and implement the event methods you want to handle. Call registerEventHandler to register your custom event handler.
const [remoteUid, setRsemoteUid] = useState(0); // Uid of the remote user
const setupEventHandler = () => {
eventHandler.current = {
// Triggered when the local user successfully joins a channel
onJoinChannelSuccess: () => {
setMessage('Successfully joined channel: ' + channelName);
setupLocalVideo();
setIsJoined(true);
},
// Triggered when a remote user joins the channel
onUserJoined: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' joined');
setRemoteUid(uid);
},
// Triggered when a remote user leaves the channel
onUserOffline: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' left the channel');
setRemoteUid(uid);
},
};
// Register the event handler
agoraEngineRef.current?.registerEventHandler(eventHandler.current);
};Note
To ensure that you receive all RTC SDK events, register the event handler before joining a channel.
Enable the video module
Call enableVideo to activate the video module, and use startPreview to enable the local video preview.
const setupLocalVideo = () => {
agoraEngineRef.current?.enableVideo();
agoraEngineRef.current?.startPreview();
};Display the local video
To display the local user's video stream, use the RtcSurfaceView component. Set the uid to 0 and style the video container.
<React.Fragment key={0}>
<RtcSurfaceView canvas={{ uid: 0 }} style={ width: '90%', height: 200 } />
</React.Fragment>Display remote video
To display the remote user's video, use the RtcSurfaceView component. Pass the remoteUid of the remote user to the component and set the desired style for the video container.
<React.Fragment key={remoteUid}>
<RtcSurfaceView
canvas={{ uid: remoteUid }}
style={ width: '90%', height: 200 }
/>
</React.Fragment>Handle permissions
To access the camera and microphone, ensure that the user grants the necessary permissions when the app starts.
On Android devices, pop up a prompt box to obtain permission to use the microphone and camera.
// Import components related to Android device permissions
const getPermission = async () => {
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
PermissionsAndroid.PERMISSIONS.CAMERA,
]);
}
};In Xcode, open the info.plist file and add the following content to the list on the right to obtain the corresponding device permissions:
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | The purpose of using the microphone, for example, for a call or live interactive streaming. |
| Privacy - Camera Usage Description | String | The purpose of using the camera, for example, for a call or live interactive streaming. |
Leave the channel
To exit a Realtime Communication channel, call leaveChannel.
const leave = () => {
// Leave the channel
agoraEngineRef.current?.leaveChannel();
setIsJoined(false);
};Clean up resources
Before closing your client, unregister the event handler and call release to free up resources.
const cleanupAgoraEngine = () => {
return () => {
agoraEngineRef.current?.unregisterEventHandler(eventHandler.current!);
agoraEngineRef.current?.release();
};
};Note
After calling release, methods and callbacks of the SDK are no longer available. To use the SDK functions again, create a new engine instance.
Complete sample code
A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy the code into ProjectName/App.tsx to quickly implement the basic functionality.
Create a user interface
Design a user interface for your project based on your application use-case. A basic interface consists of two view frames to display local and remote videos. Add Join channel and Leave channel buttons to enable the user to join and leave a channel. To create such an interface, refer to the following code:
Sample code to create the user interface
import React, { useState } from 'react';
// Import user interface elements
import {
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
Switch,
} from 'react-native';
const localUid = 0; // Local user Uid, no need to modify
const App = () => {
const [isJoined, setIsJoined] = useState(false); // Whether the local user has joined the channel
const [isHost, setIsHost] = useState(true); // User role
const [remoteUid, setRemoteUid] = useState(0); // Uid of the remote user
const [message, setMessage] = useState(''); // User prompt message
// Render user interface
return (
<SafeAreaView style={styles.main}>
<Text style={styles.head}>Agora RTC SDK quickstart</Text>
<View style={styles.btnContainer}>
<Text onPress={join} style={styles.button}>
Join Channel
</Text>
<Text onPress={leave} style={styles.button}>
Leave Channel
</Text>
</View>
<View style={styles.btnContainer}>
<Text>Audience</Text>
<Switch
onValueChange={switchValue => {
setIsHost(switchValue);
if (isJoined) {
leave();
}
}}
value={isHost}
/>
<Text>Host</Text>
</View>
<ScrollView
style={styles.scroll}
contentContainerStyle={styles.scrollContainer}>
{isJoined && isHost ? (
<React.Fragment key={localUid}>
<Text>Local user uid: {localUid}</Text>
</React.Fragment>
) : (
<Text>Join a channel</Text>
)}
{isJoined && remoteUid !== 0 ? (
<React.Fragment key={remoteUid}>
<Text>Remote user uid: {remoteUid}</Text>
</React.Fragment>
) : (
<Text>{isJoined && !isHost ? 'Waiting for remote user to join' : ''}</Text>
)}
<Text style={styles.info}>{message}</Text>
</ScrollView>
</SafeAreaView>
);
};
// Define user interface styles
const styles = StyleSheet.create({
button: {
paddingHorizontal: 25,
paddingVertical: 4,
fontWeight: 'bold',
color: '#ffffff',
backgroundColor: '#0055cc',
margin: 5,
},
main: { flex: 1, alignItems: 'center' },
scroll: { flex: 1, backgroundColor: '#ddeeff', width: '100%' },
scrollContainer: { alignItems: 'center' },
videoView: { width: '90%', height: 200 },
btnContainer: { flexDirection: 'row', justifyContent: 'center' },
head: { fontSize: 20 },
info: { backgroundColor: '#ffffe0', paddingHorizontal: 8, color: '#0000ff' },
});
export default App;Test the sample code
Take the following steps to test the sample code:
-
Update the values for
appId,token, andchannelNamein your code. -
Run the app.
Caution
Some simulators may not support all the functions of this project. Best practice is to run the project on a physical device.
To run the client on an Android device:
-
Turn on the developer options of the Android device and connect the Android device to the computer through a USB cable.
-
In the project root directory, execute
npx react-native run-android.
To run the client on an iOS device:
-
Open the
ProjectName/ios/ProjectName.xcworkspacefolder using Xcode. -
Connect the iOS device to your computer through a USB cable.
-
In Xcode, click the Build and Run button.
Note
For detailed steps on running the app on a real Android or iOS device, refer to Running On Device.
-
-
Launch the app and click the Join channel button to join a channel.
-
Invite a friend to install and run the client on a second device. Alternatively, use the Web demo to join the same channel. Once your friend joins the channel, you can see and hear each other.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
- If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.
Next steps
After implementing the quickstart sample, read the following documents to learn more:
- To ensure communication security in a test or production environment, best practice is to obtain and use a token from an authentication server. For details, see Secure authentication with tokens.
Sample project
Agora provides open source sample projects on GitHub for your reference. Download or view the JoinChannelVideo project for a more detailed example.
