Android Video Call: How to Build a Video Chat with ZEGOCLOUD API
There’s no better way of making a visually appealing call than using video call technology. This method of calling promotes interactivity at its peak, as the people involved in the call can see each other and express themselves better in real-time.
The video call technology is available on many devices or platforms, but for specificity, we’ll focus on how to video call on Android. Without further ado, let’s get started!
Must-have Features of Android Video Call
Although many video call Android apps exist today, they have some overlapping features. Video calls on Android won’t be the same without these features.
Without wasting much time, below are the must-have features of Android video call apps:
1. Sign-up & sign-in
Users have to sign up for your platform to make an account. Integrate your app with Google, Twitter, and/or Facebook so that people can sign up using their favourite social network. When setting up a profile, users can give you personal information that can help them later when they browse and use the platform.
2. List of contacts
A video chat app must have a way to add people to a list. It would also be great if users could look for each other by name, nickname, email address, and phone number.
3. Video & voice calls
This is what most online video chat programs are used for. Users should be able to make calls to one person or to a group.
4. Messages
Video calls aren’t always the best choice. Make sure users can text each other if they want to.
5. Presence status
There should also be presence statuses in your app. Users should be able to say whether they’re available or not. You can also add “active,” “busy,” and “do not disturb” as statuses.
6. Notifications
Tell users about upcoming calls, new messages, or anything else that’s going on.
7. Sharing the screen
Users will like being able to show documents, presentations, pictures, and videos on their device to coworkers, customers, and friends without having to send any files.
8. Video call recording
An important part of team or internal meetings is the ability to record. Employees can record and save a video conference call so they can watch it again, share it with others, or go over the project details again.
How to Build Video Call on Android with ZEGOCLOUD API/SDK
All through this article, we’ve talked about the features of video call apps, and you can see that the technology is indeed very cool. From what we’ve talked about so far, you can tell that making this kind of app is not easy.
People say, “There’s a way out of every problem.” In this case, ZEGOCLOUD’s Video Call SDK is the way to simplify the process of making an Android video call app. If you’re wondering what this SDK is for, just wait until we get to the next section.
Video Call SDK Introduction
ZEGOCLOUD’s Video Call (the Express-Video SDK) makes it easy to add reliable and efficient video calling and interactive live video streaming to mobile, desktop, and web apps for a wide range of use cases, such as one-on-one and group video calls, online education, live video streaming for entertainment, and more.
With just four easy steps, your applications can use ZEGOCLOUD’s cloud streaming platform to send high-quality, interactive video to your end users on all platforms with support for massive concurrency, giving them a perfect live video experience.
Why Use Video Call SDK
You might be wondering why you need the ZEGOCLOUD Video Call SDK to make your Android video call apps. Here are some of the reasons:
1. Keep in touch from anywhere in the world
The real-time communications network of ZEGOCLOUD covers more than 200 countries and regions, giving users all over the world a great audio and video experience in real-time.
With advanced QoS strategies that use adaptive jitter buffering (AJB) and forward error correction (FEC), ZEGOCLOUD can provide stable and smooth real-time communications services even when the network is slow and up to 70% of packets are lost.
Uses fully optimized algorithms to predict available network bandwidth based on current network quality data and automatically changes stream publishing and playback to control network traffic based on network conditions.
2. Quality video on a large scale
Even when the network is slow or there are a lot of people using it at once, the video quality stays high and stays the same.
3. Send and receive live video feeds from anywhere in the world.
Send full-band 48kHz samples in real-time to ensure crystal-clear conversations.
Distracting echoes and background noises can be eliminated with state-of-the-art audio processing technologies including acoustic echo cancellation (AEC), automatic noise suppression (ANS), and automatic gain control (AGC).
You may make sure your video streams smoothly by adjusting the encoding settings to the current network conditions.
4. Audio and video manipulation with artificial intelligence.
High-quality video and audio are supported, allowing for an immersive listening experience with features like 3D audio, AI-powered noise suppression, and facial improvement.
Preparation
- Have a ZEGOCLOUD developer account–Sign up
- Android device or AVD with support for video and audio.
- Latest version of Android studio or at least the 2020 and above versions.
- A basic understanding of Android app development.
Video Call SDK Integration**
To build our Android Video call application, please follow the steps below to integrate the SDK into your project.
Create a project
The first step to creating any app is actually creating a project on Android studio. You can skip this step if you already have the project created.
Follow the steps below to create a project on Android studio:
- Choose File → New → New project in Android Studio’s menu bar.
Set the Application name and the Project location for your new project.
- If you’re OK with the panel’s default settings, click Next, and then Finish.
Import SDK
Follow the steps below to import Video Call SDK into the project we created:
- When using Android Gradle Plugin v7.1.0 or later: Locate the
settings.gradle
file in the project’s root directory, open it, and insert the following codes into thedependencyResolutionManagement
section:
...
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url 'https://jitpack.io' }
google()
mavenCentral()
}
}
- If you’re using a version of the Android Gradle Plugin older than 7.1.0: In the root of your project, open the
build.gradle
file and add the following codes to theallprojects
:
...
allprojects {
repositories {
maven { url 'https://www.jitpack.io' }
google()
mavenCentral()
}
}
- If your Android Gradle Plugin version is older than v7.1.0, you will not see the aforementioned fields in
settings.gradle
. - Just edit the
build.gradle
file in the app directory and add the following line to the dependencies section. To get the most up-to-date version number, visit ZEGO Express-Video Android SDK Release History and enter “x.y.z” where “x.y.z” is the SDK version number.
...
dependencies {
...
implementation 'com.github.zegolibrary:express-video:2.+'
}
Add permissions
We need permission from Android operating system to access some of its resources like camera and microphone. We can set permission using the steps below:
- The following code should be added to the
AndroidManifest.xml
file located in the app’s source folder:
<!-- Permissions required by the SDK -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- Permissions required by the App -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Prevent class name obfuscation
The following code can be added to the proguard-rules.pro file to stop the obfuscation of the public class names in the ZEGO SDK.
-keep class **.zego.**{*;}
Implement a basic video call
Before we proceed with the implementation of video call functionality. There are some basic concepts that will help you to understand how the SDK renders video and audio. Below are those basic concepts.
- Stream publishing is the process by which the client app takes audio and video streams and sends them to the ZEGO Real-Time Audio and Video Cloud.
- Stream playing is when a client app gets audio and video streams from the ZEGO Real-Time Audio and Video Cloud and plays them.
- Room is the group-organizing service that lets people in the same room send and receive audio, video, and messages in real-time. You have to log in to a room before you can publish or play a stream. Users can only be alerted to changes in the room they are currently in.
That being said, the diagram below shows what happens when User A plays a stream that User B published:
You should know how ZEGOCLOUD’s Video Call works by now. It’s time to write some code!
Initialize the SDK
Create the UI
You need to design a video call user interface for your project that fits the needs of your use case. Since we are building an Android video call app, the following user interface components should be included in your project:
- A view for local video preview
- A view for remote video
- A Stop button
It should look like the one in the image below. The white space is for local video preview, the black one is for remote video, and the red button is for call operations:
Import header files
import im.zego.zegoexpress.ZegoExpressEngine;
import im.zego.zegoexpress.callback.IZegoDestroyCompletionCallback;
import im.zego.zegoexpress.callback.IZegoEventHandler;
import im.zego.zegoexpress.constants.ZegoPlayerState;
import im.zego.zegoexpress.constants.ZegoPublisherState;
import im.zego.zegoexpress.constants.ZegoRoomStateChangedReason;
import im.zego.zegoexpress.constants.ZegoScenario;
import im.zego.zegoexpress.constants.ZegoStreamQualityLevel;
import im.zego.zegoexpress.constants.ZegoUpdateType;
import im.zego.zegoexpress.entity.ZegoCanvas;
import im.zego.zegoexpress.entity.ZegoEngineProfile;
import im.zego.zegoexpress.entity.ZegoRoomConfig;
import im.zego.zegoexpress.entity.ZegoStream;
import im.zego.zegoexpress.entity.ZegoUser;
ZegoExpressEngine engine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Before starting a call, request the camera and recording permissions.
requestPermission();
// Set a listener for the call starting button.
findViewById(R.id.startButton).setOnClickListener(new View.OnClickListener() {
// Click to start a call.
@Override
public void onClick(View view) {
// Create a ZegoExpressEngine instance.
createEngine();
// Listen for common events.
setEventHandler();
// Log in to a room.
loginRoom();
// Start the preview and stream publishing.
startPublish();
}
});
// Set a listener for the call stopping button.
findViewById(R.id.stopButton).setOnClickListener(new View.OnClickListener() {
// Click to stop a call.
@Override
public void onClick(View view) {
engine.logoutRoom();
ZegoExpressEngine.destroyEngine(new IZegoDestroyCompletionCallback() {
@Override
public void onDestroyCompletion() {
// Successfully destroyed.
}
});
}
});
}
// Request the camera and recording permissions.
private void requestPermission() {
String[] permissionNeeded = {
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO"};
if (ContextCompat.checkSelfPermission(getApplicationContext(), "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(getApplicationContext(), "android.permission.RECORD_AUDIO") != PackageManager.PERMISSION_GRANTED) {
requestPermissions(permissionNeeded, 101);
}
}
Create a ZegoExpressEngine instance
Call the createEngine
method and use the applied AppID
and AppSign
as the values for the appID
and appSign
parameters.
// Log in to a room.
void loginRoom() {
// The `ZegoUser` constructor `public ZegoUser(String userID)` will set `userName` to the value of `userID`. The `userID` and `userName` parameters cannot be set to `null`. Otherwise, logging in to a room will fail.
ZegoUser user = new ZegoUser("user2");
ZegoRoomConfig roomConfig = new ZegoRoomConfig();
// If you use the AppSign for authentication, you do not need to set the `token` parameter. If you want to use the Token for authentication, which is securer, see [Guide for upgrading the authentication mode from using the AppSign to Token](https://docs.zegocloud.com/faq/token_upgrade).
//roomConfig.token = ;
// The `onRoomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `true` is passed.
roomConfig.isUserStatusNotify = true;
// The value of `roomID` is generated locally and must be globally unique. Users must log in to the same room to call each other.
String roomID = "room1";
// Log in to a room.
engine.loginRoom(roomID, user, roomConfig, (int error, JSONObject extendedData)->{
// Room login result. This callback is sufficient if you only need to check the login result.
if (error == 0) {
// Login successful.
Toast.makeText(this, "Login successful.", Toast.LENGTH_LONG).show();
} else {
// Login failed. For details, see Error codes doc.
Toast.makeText(this, "Login failed. For details, see [Error codes](https://docs.zegocloud.com/article/5548).", Toast.LENGTH_LONG).show();
}
});
}
Sign in to a room
To sign in to a room, call the loginRoom
method. If the room doesn’t already exist, calling this method will create it and sign you in. The values of the roomID and user parameters are made locally, but the following conditions must be met:
- Under the same
AppID
, the value ofroomID
must be unique globally. - Under the same
AppID
, the value ofuserID
must be unique everywhere. You should connect userID
with your service’s account system.
// Log in to a room.
void loginRoom() {
// The `ZegoUser` constructor `public ZegoUser(String userID)` will set `userName` to the value of `userID`. The `userID` and `userName` parameters cannot be set to `null`. Otherwise, logging in to a room will fail.
ZegoUser user = new ZegoUser("user2");
ZegoRoomConfig roomConfig = new ZegoRoomConfig();
// If you use the AppSign for authentication, you do not need to set the `token` parameter. If you want to use the Token for authentication, which is securer, see [Guide for upgrading the authentication mode from using the AppSign to Token](https://docs.zegocloud.com/faq/token_upgrade).
//roomConfig.token = ;
// The `onRoomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `true` is passed.
roomConfig.isUserStatusNotify = true;
// The value of `roomID` is generated locally and must be globally unique. Users must log in to the same room to call each other.
String roomID = "room1";
// Log in to a room.
engine.loginRoom(roomID, user, roomConfig, (int error, JSONObject extendedData)->{
// Room login result. This callback is sufficient if you only need to check the login result.
if (error == 0) {
// Login successful.
Toast.makeText(this, "Login successful.", Toast.LENGTH_LONG).show();
} else {
// Login failed. For details, see Error codes doc.
Toast.makeText(this, "Login failed. For details, see [Error codes](https://docs.zegocloud.com/article/5548).", Toast.LENGTH_LONG).show();
}
});
}
Start local video preview
You can test to see if your setup is working by starting a local video preview. You can do this by setting the preview view and start
the local video preview by calling the startPreview
method.
Publish streams to the audio and video cloud provided by ZEGOCLOUD.
After calling the loginRoom
method, you can call the startPublishingStream
method and pass the streamID
to send the audio and video streams to the ZEGOCLOUD audio and video cloud.
// Preview and publish streams.
void startPublish() {
// Set the local preview view and start the preview. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
ZegoCanvas previewCanvas = new ZegoCanvas(findViewById(R.id.preview));;
engine.startPreview(previewCanvas);
// Start to publish streams.
// After calling the `loginRoom` method, call this method to publish streams.
// Ensure that the value of `streamID` is globally unique under the same AppID. If different streams are published with the same `streamID`, the ones that are published after the first one will fail.
engine.startPublishingStream("stream2");
}
Play streams
During a video call, other users’ audio and video streams must be played.
When another user in the same room publishes audio and video streams to the ZEGOCLOUD audio and video cloud, you will be notified through the onRoomStreamUpdate callback and can get the streamID
of a certain stream through ZegoStream
.
You can play the user’s audio and video stream by calling startPlayingStream
in the callback and passing the value of streamID
. You can listen for the playing state with the onPlayerStateUpdate
callback.
// Listen for the playing status.
void setEventHandler() {
engine.setEventHandler(new IZegoEventHandler() {
@Override
// When another user in the same room publishes or stops publishing streams, you will receive a notification of stream increase or decrease of the user.
public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoStream> streamList, JSONObject extendedData) {
super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);
// When `updateType` is set to `ZegoUpdateType.ADD`, an audio and video stream is added, and you can call the `startPlayingStream` method to play the stream.
if (updateType == ZegoUpdateType.ADD) {
// Start to play streams. Set the view for rendering the remote streams. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
ZegoStream stream = streamList.get(0);
String playStreamID = stream.streamID;
// In the following code, the value of `remoteUserView` is the same as that of `TextureView` of the UI. For the conciseness of the sample code, only the first stream in the list of newly added audio and video streams is played here. In a real service, it is recommended that you traverse the stream list to play each stream.
ZegoCanvas playCanvas = new ZegoCanvas(findViewById(R.id.remoteUserView));
engine.startPlayingStream(playStreamID, playCanvas);
}
}
});
}
Stopping a video call
Stopping stream publishing
If you want to stop broadcasting local audio and video to remote users, you can do so by calling the stopPublishingStream
method:
// Stop publishing streams.
engine.stopPublishingStream();
Stopping local preview
You can stop local preview by calling the stopPreview
method.
// Stop the local preview.
engine.stopPreview();
Stop playing streams
To stop playing a user-uploaded audio or video stream, use the stopPlayingStream
function.
// Stop playing streams.
engine.stopPlayingStream("stream1");
Sign out of a room
To log out of a room, Call the logoutRoom
method.
Destroy a ZegoExpressEngine instance
If you’re done with a video call, and want to destroy the instance, you can do so by calling destroyEngine
method.
ZegoExpressEngine.destroyEngine(null);
Run a demo.
Conclusion
ZEGOCLOUD Video Call SDK saves you a lot of time by allowing you to quickly build a Video Call App through simple steps without worrying about how everything works. With little coding knowledge, you can get your app up and running.
Download the sample demo source code from this article if you’re interested in creating audio and video applications.