Imagine having the power to create personalized video experiences within your app. That’s exactly what Agora’s Video Calling offers! With Agora’s Video SDK, you can effortlessly integrate real-time video capabilities into any application.
The best part? You have complete control over a wide range of exciting features. Want to enable recording or implement content moderation? It’s all possible! And if you’re looking to take things up a notch, Agora’s Extensions Marketplace has got you covered. Activate background removal, add fun face filters, and so much more in just a few clicks. Let’s dive into this blog tutorial and learn how to get started with Agora’s Video Calling for your Android app!
There are a variety of options available for developers that can help them incorporate real-time communication in their apps. This is where Agora plays an important role and becomes a distinguished choice. Let’s find out what sets it apart from its counterparts for the developers to extract the full potential of real-time video. Here are the major highlights:
Seamless integration: The Video Software Development Kit i.e. SDK is an integral part of Agora. It makes the integration of real-time video capabilities with Android Apps quite simple and convenient. This works across a diverse set of usage whether it’s for a virtual event, a telemedicine based app, or a communication-based app, Agora’s SDK can provide a seamless execution throughout.
Global network infrastructure: Its Software Defined Real-time Network (Agora SD-RTN™) is extremely capable and globally accepted for enabling top-quality video and audio without any geographical constraints. This wards off any prospective obstructions in terms of network and ensures that the user experiences quality consistently.
Feature-rich toolkit: Agora comes along with a high-tech feature-rich toolkit that leads to customized video creation. It also allows users additional functions like call recording, content moderation, screen sharing, and much more without much ado. It’s possible to unlock these features with just a few lines of coding. One can empower the whole set-up with Extensions Marketplace and can also add fun filters, face filters, or even activate background removal.
Developer-friendly documentation: Agora is an intelligent tool and it understands how essential clarity is when it comes to documentation. It also effectively customizes data in comprehensive information as resources whether it is code samples, detailed guidebooks, and much more. The community that it leads is also active, making it easy to solve and troubleshoot any issue.
Security and privacy: Agora has a strong build-up for maintaining the security and privacy of your users’ data. Hence, it becomes reliable enough that users can implement and integrate Agora for real-time video communication without any second thought. Its framework is robust to ensure sensitive information stays private.
Scalability: Agora’s framework is such that scalability and expansion of any kind is possible. Whether an app begins with a limited user base and later grows on to expand it to double or even ten times, its infrastructure will support the growth with ease.
Audio enhancement: You can enjoy a seamless audio experience with Agora, thanks to its AI-powered audio enhancement features. It provides a communication driven with clarity. The highlight feature is 3D spatial audio to noise suppression which allows you to gain control.
Transparent pricing: There are a lot of pricing brackets offered by Agora to ensure the availability of cost-effective solutions for your App. One can explore the options and choose one that will suit the specific needs of your project. The details of packages are updated on its pricing page.
Community and support resources: By joining Agora’s developer community you will get access to its support resources like forums and documentation. This will help enhance your development skills and also help you with resolutions to specific issues you may face in the interface.
Agora has become the ideal choice for a diverse set of use cases mainly owing to its flexibility and power. Here’s a list of a few scenarios where it has made an extraordinary impact:
Use Cases | Description |
---|---|
Conferencing apps | In today’s world where remote work and global collaborations have become quite common, conferencing apps have gained a lot of popularity as they have become indispensable for businesses. Agora provides seamless solutions, hence empowering developers. They are able to create secure and feature-rich real-time video communication-based solutions, enabling assorted geographical teams to collaborate virtually and brainstorm. |
Telemedicine applications | Healthcare is an essential service and is frequented in emergencies. Agora’s Video Calling SDK simplifies telemedicine applications. It makes the process of online consultation convenient as healthcare providers can diagnose patients remotely and provide advice or medical guidance as requisite in real-time. |
Virtual events | There are many events; both formal and informal, that are now conducted virtually. Hence, virtual events powered by Agora play a very important role where physical gatherings are not required. The events can be of any magnitude from virtual expos and trade shows to online concerts and conferences, Agora’s SDK can support it irrespective, thus providing a chance for the participants to engage and network online in real-time. |
Online education platforms | Online education-based platforms benefit the most from Agora’s Video Calling SDK as it provides the real-time continuity it essentially requires in virtual classrooms. The teachers and students are able to interact and the experience of face-to-face learning continues. The students can ask questions in real-time and the teachers can explain with examples just as they would in any classroom setting. |
Social networking apps | Social networking apps have become the medium to develop and sustain human connections in today’s time. Agora makes these platforms more interesting by enabling live video chats, interactive streaming, or virtual meetups. So it becomes easy to manage connections virtually with it as it helps with real-time communication. |
Live streaming and broadcasting | Live streaming and broadcasting have become an everyday routine for social media influencers and digital content creators. It makes it easy for them to maintain continual relationships with their followers and community. Hence with real-time connectivity offered by Agora, they can interact live, host Q&A, respond to queries, etc. |
These instances are only a few, however, the possibilities of doing so much more lie ahead with its Video Calling SDK’s potential. One can think of designing innovative apps and platforms based on networking, and then let Agora do the rest.
Now let’s jump into the code to add high-quality, low-latency Video Calling features to your app!
Android Studio 4.1 or higher
Android SDK API Level 24 or higher
A smartphone that runs Android 4.1 or higher
An Agora account and project
To start integrating Agora Video Calling into your app you can follow these steps:
Add dependency to your build.gradle(app) file.
dependencies {
...
// Agora
implementation 'io.agora.rtc:<artifact id>:<version>'
...
}
<artifact id> and <version> can be found with the maven repository – search here.
Add the following permissions to your project’s AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- The Agora SDK requires Bluetooth permissions in case users are using Bluetooth devices. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- For Android 12 and above devices, the following permission is also required. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
If your project obfuscates the code, then add the following line to your proguard-rules.pro file.
-keep class io.agora.**{*;}
Also read – Flutter AR Integration: A Complete How-To Guide
Now it is time to integrate UI and code for the Agora Video Calling. In order to keep the tutorial simple, we will keep the code short and implement 1:1 calling.
Here are the implementation of XML files for Agora. Add them to your res/layout package.
This is activity_agora_video.xml, here we have added cvVideoControls, which contains controls like mute, pause video, switch front and back camera, and end call buttons. Users can perform actions as required. ivOtherUsersMicStatus and ivOtherUsersVideoStatus are visible when the user on the opposite side of the video call mutes their mike or pauses their video.
We have included the layout_video_call, you can scroll down after this code snippet to understand.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type=".viewmodel.AgoraVideoCallViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/clRootContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.AgoraVideoActivity">
<include android:id="@+id/layoutVideos" layout="@layout/layout_video_call"/>
// Controls for CardView
<androidx.cardview.widget.CardView
android:id="@+id/cvVideoControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="16dp"
android:visibility="visible"
app:cardCornerRadius="8dp"
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/ivSwitchCamera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:paddingVertical="16dp"
android:src="@drawable/ic_flip_camera" />
<ImageView
android:id="@+id/ivVideoToggle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:paddingVertical="16dp"
android:src='@{viewModel.isVideoEnabled() ? @drawable/ic_videocam : @drawable/ic_videocam_off, default="@drawable/ic_videocam"}' />
<ImageView
android:id="@+id/ivMicToggle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:paddingVertical="16dp"
android:src='@{viewModel.isMicEnabled() ? @drawable/ic_mic : @drawable/ic_mic_off, default="@drawable/ic_mic"}' />
<ImageView
android:id="@+id/ivCallEnd"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:paddingVertical="16dp"
android:src="@drawable/ic_call_end"
app:tint="@color/bt_error_red" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<ImageView
android:id="@+id/ivOtherUsersMicStatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:padding="16dp"
android:src='@drawable/ic_mic_off'
android:visibility='@{viewModel.isOtherUsersMicEnabled() ? View.GONE : View.VISIBLE, default="gone"}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/white"
tools:visibility="visible" />
<ImageView
android:id="@+id/ivOtherUsersVideoStatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?actionBarItemBackground"
android:padding="16dp"
android:src='@drawable/ic_videocam_off'
android:visibility='@{viewModel.isOtherUsersVideoEnabled() ? View.GONE : View.VISIBLE, default="gone"}'
app:layout_constraintEnd_toStartOf="@+id/ivOtherUsersMicStatus"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/white"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
This is layout_video_call.xml. In this file, we have included 2 FrameLayout containers, which will hold the SurfaceView of the Video Call. flVideoContainer_1 is used to show local camera preview and flVideoContainer_2 is used to show a preview of the other user.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/flVideoContainer_1"
android:layout_width="96dp"
android:layout_height="128dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="78dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<FrameLayout
android:id="@+id/flVideoContainer_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is the implementation for your AgoraVideoActivity.kt.
class AgoraVideoActivity : AppCompatActivity {
private val viewModell by viewModels<AgoraVideoCallViewModel>()
private val appId = // Agora App Id
private lateinit var channelName: String
private lateinit var token: String
private var uid: Int = // User’s ID
private var agoraEngine: RtcEngine? = null
private val REQUESTED_PERMISSIONS = arrayOf<String>(
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
)
...
...
}
Check if camera and Microphone permissions are provided with this method.
private fun checkSelfPermission(): Boolean {
return !(ContextCompat.checkSelfPermission(
this,
REQUESTED_PERMISSIONS[0]
) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, REQUESTED_PERMISSIONS[1]) != PackageManager.PERMISSION_GRANTED)
}
Here, we will initialize members and set up click listeners of buttons. If we already have the required user permission, we can set up the video sdk engine. If not, we can handle the user permission acquiring flow.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initializeMembers() // <-- Initialize your members here
setupClickListeners()
if (checkSelfPermission()) {
setupVideoSDKEngine()
joinChannel()
} else {
// Acquiring user permission logic here
}
}
private fun setupClickListeners() {
binding.ivCallEnd.setOnClickListener {
leaveChannel()
finish()
}
binding.ivSwitchCamera.setOnClickListener {
agoraEngine?.switchCamera()
}
binding.ivVideoToggle.setOnClickListener {
if (safeUnbox(viewModel.isVideoEnabled)) {
agoraEngine?.enableLocalVideo(false)
} else {
agoraEngine?.enableLocalVideo(true)
}
viewModel.toggleVideoEnabled()
}
binding.ivMicToggle.setOnClickListener {
if (safeUnbox(viewModel.isMicEnabled)) {
agoraEngine?.muteLocalAudioStream(true)
} else {
agoraEngine?.muteLocalAudioStream(false)
}
viewModel.toggleMicEnabled()
}
}
// Stop the agora engine. If not done, videocall will continue until the app closed.
override fun onDestroy() {
super.onDestroy()
agoraEngine!!.leaveChannel()
Thread {
RtcEngine.destroy()
agoraEngine = null
}.start()
}
private val mRtcEventHandler: IRtcEngineEventHandler = object : IRtcEngineEventHandler() {
// Listen for the remote host joining the channel to get the uid of the host.
override fun onUserJoined(uid: Int, elapsed: Int) {
showMessage("Remote user joined $uid")
logD("Remote user joined $uid")
runOnUiThread { setupRemoteVideo(uid) }
}
override fun onUserOffline(uid: Int, reason: Int) {
showMessage("Remote user offline $uid $reason")
logD("Remote user offline $uid $reason")
}
override fun onJoinChannelSuccess(channel: String, uid: Int, elapsed: Int) {
viewModel.setJoined(true)
showMessage("Joined Channel $channel")
}
override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {
super.onRemoteAudioStateChanged(uid, state, reason, elapsed)
if (uid != this@AgoraVideoActivity.uid) viewModel.opponentMicOn(state != Constants.REMOTE_AUDIO_STATE_STOPPED && reason != Constants.REMOTE_AUDIO_REASON_REMOTE_MUTED)
}
override fun onRemoteVideoStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {
super.onRemoteVideoStateChanged(uid, state, reason, elapsed)
if (uid != this@AgoraVideoActivity.uid) viewModel.opponentVideoOn(state != Constants.REMOTE_VIDEO_STATE_STOPPED && reason != Constants.REMOTE_VIDEO_STATE_REASON_REMOTE_MUTED)
}
}
private fun setupVideoSDKEngine() {
try {
val config = RtcEngineConfig()
config.mContext = baseContext
config.mAppId = appId
config.mEventHandler = mRtcEventHandler
agoraEngine = RtcEngine.create(config)
// By default, the video module is disabled, call enableVideo to enable it.
agoraEngine?.enableVideo()
} catch (e: Exception) {
showMessage(e.toString())
}
}
private fun showMessage(string: String) {
// make sure to use runOnUiThread, otherwise may end up with the app crashing without proper error message
runOnUiThread { toast(string) }
}
Here, we set up the SurfaceView for video calling. Since our local video stream SurfaceView is going to be above the SurfaceView of the remote video stream, we have to set the setZOrderOnTop(true) in order to show the video above the remote video. If it is not done, you will not be able to preview the local video stream.
private fun setupLocalVideo() {
val container = binding.layoutVideos.flVideoContainer1
container.removeAllViews()
// Create a SurfaceView object and add it as a child to the FrameLayout.
val localSurfaceView = SurfaceView(baseContext)
localSurfaceView.setZOrderOnTop(true)
container.addView(localSurfaceView)
// Call setupLocalVideo with a VideoCanvas having uid set to 0.
agoraEngine!!.setupLocalVideo(VideoCanvas(localSurfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid))
}
private fun setupRemoteVideo() {
val container = binding.layoutVideos.flVideoContainer2
container.removeAllViews()
val remoteSurfaceView = SurfaceView(baseContext)
container.addView(remoteSurfaceView)
agoraEngine!!.setupRemoteVideo(VideoCanvas(remoteSurfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid))
}
As the name suggests, we join the video call with this function.
fun joinChannel() {
if (checkSelfPermission()) {
val options = ChannelMediaOptions()
// For a Video call, set channel profile as COMMUNICATION.
options.channelProfile = Constants.CHANNEL_PROFILE_COMMUNICATION
// Set the client role as BROADCASTER or AUDIENCE according to the scenario.
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER
// Display LocalSurfaceView.
setupLocalVideo()
// Start local preview.
agoraEngine!!.startPreview()
// Join the channel with a temp token.
// You need to specify the user ID yourself, and ensure that it is unique in the channel.
agoraEngine!!.joinChannel(token, channelName, uid, options)
} else {
Toast.makeText(applicationContext, "Permissions was not granted", Toast.LENGTH_SHORT).show()
}
}
fun leaveChannel() {
if (!safeUnbox(viewModel.isJoined)) {
showMessage("Join a channel first")
} else {
agoraEngine!!.leaveChannel()
}
}
Our ViewModel will emit the actions performed on Video Controls, and the view will react to the changes with DataBinding.
class AgoraVideoCallViewModel : BaseViewModel() {
var isJoined = MutableLiveData(false)
var isVideoEnabled = MutableLiveData(true)
var isMicEnabled = MutableLiveData(true)
var isOtherUsersMicEnabled = MutableLiveData(true)
var isOtherUsersVideoEnabled = MutableLiveData(true)
fun setJoined(value: Boolean) {
isJoined.postValue(value)
}
fun toggleVideoEnabled() {
isVideoEnabled.postValue(!isVideoEnabled.value!!)
}
fun toggleMicEnabled() {
isMicEnabled.postValue(!isMicEnabled.value!!)
}
fun opponentMicOn(isOn: Boolean) {
isOtherUsersMicEnabled.postValue(isOn)
}
fun opponentVideoOn(isOn: Boolean) {
isOtherUsersVideoEnabled.postValue(isOn)
}
}
Also read: Choosing the Right Tool: Jetpack Compose vs. XML for Android UI
Agora offers a range of powerful features that enhance your video-calling experience. With call recording, you can conveniently store and control the format, storage path, and quality of your calls. Screen sharing and collaboration enable users to share their screens, utilize interactive whiteboards, and collaborate on content across multiple devices simultaneously.
With support for multiple audio and video tracks, you can easily publish them to one or more channels from a single instance, accommodating multi-channel capture cameras and microphones. Agora ensures consistent high-quality video, whether you’re making a one-on-one call or hosting thousands of concurrent users, even in challenging network conditions. With AI-powered audio enhancement, you can enjoy crystal-clear audio with features like 3D spatial audio, AI noise suppression, and gain control. Agora’s global coverage extends its reach to users in over 200 countries and regions, thanks to its software-defined, real-time network (SD-RTN).
It is essential to optimize Agora’s Video Calling SDK’s performance as per the Android App to ensure that user experience stays valuable and hassle-free. Here are a few best practices and expert tips that can be implemented to properly utilize its capabilities:
Network conditions: Network conditions impact the quality of real-time communication. Hence, to experience the App in the best way possible, it is important you suggest the use of a stable high-speed internet connection to your users. Software Defined Real-time Network (SD-RTN™) of Agora is intelligent enough to adapt to the network fluctuations, however, a strong connection can still be convenient.
Audio and video quality: To experience high-quality of audio and video, the users must use good-quality microphones and cameras. If they are connecting on virtual calls, their surrounding should have good light and little to no background noise. Agora does have an AI-powered noise suppression tool that can minimize noise, however, a clean input is always suggested.
Resource management: Proper resource handling is a must to effectively manage device resources. For instance, if you are not using a microphone or a camera currently, release them. This not only reduces battery drainage but also prevents heating of the device. Ultimately it adds to elongating the life of the device.
Testing and optimization: Regular testing and optimization are essential for an App to work smoothly. It is recommended that before you launch your app, you go through step-by-step testing of Agora’s integration to ensure that there is nothing missing. This ensures the real-time connectivity it can offer. Along with this, the network conditions and the multi-device set-up should also be checked.
Code optimization: The developer must follow the best practices recommended by Android to write the code. It ensures consistency and efficient working. Proper release of unused resources will help avoid memory leaks. The developers must also pay attention to threading and concurrency for smooth functionality.
UI/UX design: The video calling interface must have an innovative design that is easy to use and navigate. The control access should be convenient. One can also include visual cues as and where possible or needed for necessary actions like muting and camera switching. A quality UI/UX framework is necessary to make it user-friendly.
Error handling: It is important to make contingency plans well in advance and hence error handling processes should be implemented so as to manage unexpected errors at any given time. Users should also receive clear communication in case of any issues or disruptions. The messages they receive must provide clear error details.
Bandwidth management: Agora has certain dynamic properties that allow efficient bandwidth management. It allows dynamic adjustment of video quality to set it according to the device or network speed. It is necessary that users stay informed of bandwidth consumption, especially on metered providers.
Real-time monitoring: The real-time monitoring of call quality is now easily possible with Agora. You can implement it to seek metrics as well as decide on event listeners to analyze the performance quality of calls. This will help in the easy resolution of any pertaining issues.
Frequent updates: Agora’s SDK is regularly updated with new tools and improvement features. Hence the developers must stay up to date with its updates. You must also regularly update your app for compatibility and seek access to the latest features and improved security.
Privacy and security: Privacy and security come above everything else and should be the priority. The video calls must have end-to-end encryption. The user data should be protected as per compliance and data protection regulations.
User education: Your users need consistent educating information to be able to properly utilize the features of Agora. They must understand the importance of a good network, suitable device settings, and environment must-haves for good-quality video communication. Informed users make informed decisions.
Implementation of such best practices and by following expert tips, you’ll be able to deliver a high-quality real-time communication experience to your users through Agora’s Video Calling SDK in your Android app. Continual optimization, having an open platform for user feedback, and implementing improvements when necessary will enhance the performance of the App.
Also read – A Detailed Comparison: Native Android and Flutter App Performance
Agora has made it very easy to integrate very complex features like video calling and streaming without having to set up your streaming server or implement raw WebRTC technology into your project. This allows you to implement Video Calling into the application or website quickly and easily. They have also provided very thorough documentation, and thanks to their excellent service, Agora has grown its own community that helps resolve any issues faced during implementation.
If you want to upgrade your Android App’s performance and integrate powerful video calling features in it, then connect with us today to know how the expertise of our Android app development team can make real-time communication possible with your project. We work across diverse kinds of projects, so if you are working on a conferencing app, a telemedicine platform, or any other app that requires real-time video, we can make your task easy. Let’s collaborate to give life to your vision with Agora.