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.
-
Flutter 2.10.5 or higher with Dart 2.14.0 or higher.
-
Android Studio, IntelliJ, VS Code, or another IDE that supports Flutter. See Set up an editor.
-
Prepare your development and testing environment according to your target platform.
Run
flutter doctorto confirm that your development environment is set up correctly for Flutter development.
Set up your project
From the Terminal, run the following commands to create a new project named agora_project, or follow the steps for your IDE:
flutter create agora_project
cd agora_projectTo add Realtime Communication to your existing project:
- Open your Flutter project and navigate to the
libfolder. - Add a new file to the
libfolder and name itagora_logic.dart.
Install the SDK
Install the Agora RTC SDK and other dependencies.
-
Add the latest version of Agora RTC SDK to your Flutter project:
flutter pub add agora_rtc_engine -
Add the permission processing package:
flutter pub add permission_handlerThe
dependenciesin yourpubspec.yamlfile should look like the following:dependencies: flutter: sdk: flutter agora_rtc_engine: ^6.5.0 # Agora Flutter SDK, please use the latest version permission_handler: ^11.3.1 # Package for managing runtime permissions cupertino_icons: ^1.0.8 -
Install the dependencies.
Execute the following command in the project path:
flutter pub get
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.
Import packages
Import the following packages in your dart file.
import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';Initialize the engine
For real-time communication, initialize an RtcEngine instance. Use RtcEngineContext to specify the App ID, and other configuration parameters. In your dart file, add the following code:
Unlike other platforms, Flutter sets the channel profile once, when you initialize the engine, instead of at join time. Set it 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 |
// Set up the Agora RTC engine instance
Future<void> _initializeAgoraVoiceSDK() async {
_engine = createAgoraRtcEngine();
await _engine.initialize(const RtcEngineContext(
appId: "<-- Insert app Id -->",
// Set the channel profile according to your use case (see table above)
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
));
}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.
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 clientRoleType and audienceLatencyLevel in ChannelMediaOptions according to your use case (see table above). The following example shows the configuration for interactive live streaming with the broadcaster role:
// Join a channel
Future<void> _joinChannel() async {
await _engine.joinChannel(
token: token,
channelId: channel,
options: const ChannelMediaOptions(
autoSubscribeVideo: true, // Automatically subscribe to all video streams
autoSubscribeAudio: true, // Automatically subscribe to all audio streams
publishCameraTrack: true, // Publish camera-captured video
publishMicrophoneTrack: true, // Publish microphone-captured audio
// Use clientRoleBroadcaster to act as a host, or clientRoleAudience for audience
clientRoleType: ClientRoleType.clientRoleBroadcaster,
// Only takes effect when clientRoleType is clientRoleAudience
audienceLatencyLevel: AudienceLatencyLevelType.audienceLatencyLevelLowLatency,
),
uid: 0,
);
}Subscribe to RTC SDK events
The SDK provides the RtcEngineEventHandler for subscribing to channel events. To use it, pass an instance of RtcEngineEventHandler to registerEventHandler and implement the event methods you want to handle.
Call registerEventHandler to bind the event handler to the SDK.
// Register an event handler for Agora RTC
void _setupEventHandlers() {
_engine.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
debugPrint("Local user ${connection.localUid} joined");
setState(() => _localUserJoined = true);
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
debugPrint("Remote user $remoteUid joined");
setState(() => _remoteUid = remoteUid);
},
onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {
debugPrint("Remote user $remoteUid left");
setState(() => _remoteUid = null);
},
),
);
}When a remote user joins the channel, the onUserJoined callback is triggered. Use the remote user's uid returned in the callback, to create an AgoraVideoView control for displaying the video stream from the remote user.
Note
To ensure that you receive all RTC SDK events, register the event handler before joining a channel.
Display the local video
To display the local video, enable the video module by calling enableVideo, then start the local video preview with startPreview.
Future<void> _setupLocalVideo() async {
// The video module and preview are disabled by default.
await _engine.enableVideo();
await _engine.startPreview();
}To render the local video, add the following widget inside your UI’s widget tree, such as in the build method of your StatefulWidget:
// Displays the local user's video view using the Agora engine.
Widget _localVideo() {
return AgoraVideoView(
controller: VideoViewController(
rtcEngine: _engine, // Uses the Agora engine instance
canvas: const VideoCanvas(
uid: 0, // Specifies the local user
renderMode: RenderModeType.renderModeHidden, // Sets the video rendering mode
),
),
);
}Display remote video
To render a remote video, add the following widget inside your UI’s widget tree, such as in the build method of your StatefulWidget:
// If a remote user has joined, render their video, else display a waiting message
Widget _remoteVideo() {
if (_remoteUid != null) {
return AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: _engine, // Uses the Agora engine instance
canvas: VideoCanvas(uid: _remoteUid), // Binds the remote user's video
connection: const RtcConnection(channelId: channel), // Specifies the channel
),
);
} else {
return const Text(
'Waiting for remote user to join...',
textAlign: TextAlign.center,
);
}
}Handle permissions
Request microphone and camera permissions.
Future<void> _requestPermissions() async {
await [Permission.microphone, Permission.camera].request();
}Note
If your target platform is iOS or macOS, add the microphone and camera permission declarations required for real-time interaction to Info.plist.
| Device | Key | Value |
|---|---|---|
| Microphone | Privacy - Microphone Usage Description | for audio calls |
| Camera | Privacy - Camera Usage Description | for video calls |
Start and close the app
To start Realtime Communication, request microphone and camera permissions, initialize the Agora SDK instance, set up event handlers, join a channel, and display the local video.
await _requestPermissions();
await _initializeAgoraVideoSDK();
await _setupLocalVideo();
_setupEventHandlers();
await _joinChannel();To stop Realtime Communication, leave the channel and release the engine instance.
// Leaves the channel and releases resources
Future<void> _cleanupAgoraEngine() async {
await _engine.leaveChannel();
await _engine.release();
}Note
After you call release, you no longer have access to the methods and callbacks of the SDK. To use Realtime Communication features 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 following code to replace the entire contents of the .dart file in your project.
Note
In the appId and token fields, enter the corresponding values you obtained from Agora Console. Use the same channel name you filled in when generating the temporary token.
Create a user interface
To connect the sample code to your existing UI, ensure that your widget tree includes the _remoteVideo and _localVideo widgets used to Display the local video and Display remote video.
Alternatively, use the following sample code to generate a basic user interface:
Sample code to create the user interface
// Build UI to display local video and remote video
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Agora Video Call')),
body: Stack(
children: [
Center(child: _remoteVideo()),
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
height: 150,
child: Center(
child: _localUserJoined
? _localVideo()
: const CircularProgressIndicator(),
),
),
),
],
),
);
}Test the sample code
Take the following steps to test the sample code:
-
In
main.dartupdate the values forappId, andtokenwith values from Agora Console. Fill in the samechannelname you used to generate the token. -
Connect a target device to your development computer.
-
Open Terminal and execute the following command in the project folder to run the sample project:
flutter run -
Launch the App, grant microphone and camera permissions. If you set the user role to host, you see yourself in the local view.
-
On a second target device, repeat the previous steps to install and launch the client. Alternatively, use the Web demo to join the same channel and test the following use-cases:
- If users on both devices join the channel as hosts, they can see and hear each other.
- If one user joins as host and the other as audience, the host can see themselves in the local video window; the audience can see the host in the remote video window and hear the host.
On an Android device, the app UI appears similar to the following:
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 join_channel_video.dart for a more detailed example.
