Android Video Calling Tutorial
This tutorial teaches you how to build a Zoom/Whatsapp-style video calling app.
- Calls run on Stream's global edge network for optimal latency & reliability.
- Permissions give you fine-grained control over who can do what.
- Video quality and codecs are automatically optimized.
- Powered by Stream's Video Calling API.
- UI components are fully customizable, as demonstrated in the Android Video Cookbook.
Step 1 - Create a new project in Android Studio
Confused about "Step 1 - Create a new project in Android Studio"?
Let us know how we can improve our documentation:
- Create a new project
- Select Phone & Tablet -> Empty Activity
- Name your project VideoCall.
Note that this tutorial was written using Android Studio Jellyfish. Setup steps can vary slightly across Android Studio versions. We recommend using Android Studio Jellyfish or newer.
Step 2 - Install the SDK & Setup the client
Confused about "Step 2 - Install the SDK & Setup the client"?
Let us know how we can improve our documentation:
The Stream Video SDK has two main artifacts:
- Core Client:
io.getstream:stream-video-android-core
- includes only the core part of the SDK. - Compose UI Components:
io.getstream:stream-video-android-ui-compose
- includes the core + Compose UI components.
For this tutorial, we'll use the Compose UI Components.
Add the Video Compose SDK dependency to the app/build.gradle.kts
file.
If you're new to Android, note that there are 2 build.gradle.kts
files, you want to open the one located in the app
folder.
⚠️ Replace <latest-version>
with the version number indicated below. Also, you can check the Releases page.
⚠️ Make sure compileSdk
(or compileSdkVersion
- if you're using the older syntax) is set to 34
or newer in your app/build.gradle.kts
file.
⚠️ If you get Compose-related errors when building your project, expand this section and follow the steps.
- Add the following dependencies in the
app/build.gradle.kts
file, if needed:
- Add the following lines to the
app/build.gradle.kts
file, if needed:
- Make sure you're using a Kotlin version that's compatible with the Compose compiler version specified by
kotlinCompilerExtensionVersion
above. Check this page to see which Kotlin version is compatible with your Compose Compiler version. If needed, change the Kotlin version in your project'sbuild.gradle.kts
file:
⚠️ Make sure you sync the project after doing these changes. Click on the Sync Now button above the file contents.
Step 3 - Create & Join a call
Confused about "Step 3 - Create & Join a call"?
Let us know how we can improve our documentation:
To keep this tutorial short and easy to understand, we'll place all the code in MainActivity.kt
. For a production app you'd want to initialize the client in your Application
class or DI module. You'd also want to use a View Model.
Open MainActivity.kt
and replace the MainActivity
class with the code below.
Also, you can find below the import
statements that are used throughout this tutorial. Replace the already existing import
statements to follow along easily.
You can delete the other functions that were created by Android Studio.
Import statements
To actually run this sample, we need a valid user token. The user token is typically generated by your server-side API. When a user logs in to your app, you return the user token that gives them access to the call.
We'll generate a user token for you to make this tutorial easier to follow. Please update REPLACE_WITH_API_KEY, REPLACE_WITH_TOKEN, REPLACE_WITH_USER_ID and REPLACE_WITH_CALL_ID with the actual values shown below:
Here are credentials to try out the app with:
Property | Value |
---|---|
API Key | Waiting for an API key ... |
Token | Token is generated ... |
User ID | Loading ... |
Call ID | Creating random call ID ... |
Now, when you run the sample app, it will connect successfully. The text will say, "Call <ID> has 1 participant" (yourself).
Let's review what we did in the code above.
Create a user. First, we create a user instance. You typically sync these users via a server-side integration on your own backend. Alternatively, you can also use guest or anonymous users.
Initialize the Stream Video Client. Next, we initialize the video client by passing the API Key, user, and user token.
Create the call. After the user and client are created, we create a call.
Request runtime permissions. Before joining the call, we request a camera and microphone runtime permissions to capture video and audio.
Review the permissions docs to learn more about how you can easily request permissions.
Join the call. We join the call in the onAllPermissionsGranted
block.
As soon as you use call.join()
, the connection for video and audio is set up.
Define the UI. Lastly, the UI is rendered by observing call.state
(participants and connection states).
You'll find all relevant states for the call in call.state
and call.state.participants
.
The documentation on Call state and Participant state explains this in further detail.
Step 4 - Joining from the web
Confused about "Step 4 - Joining from the web"?
Let us know how we can improve our documentation:
Let's join the call from your browser to make this a little more interactive.
On your Android device, you'll see the text update to 2 participants. Let's keep the browser tab open as you go through the tutorial.
Step 5 - Rendering Video
Confused about "Step 5 - Rendering Video"?
Let us know how we can improve our documentation:
In this next step, we're going to render the local & remote participant video feeds.
In the MainActivity.kt
file, replace the code inside VideoTheme
with the example below:
When you run the app, you'll see your local video in a floating video element and the video from your browser. The result should look somewhat like this:
Let's review the changes we made.
ParticipantVideo renders a participant based on ParticipantState in a call. If the participant's track is not null and is correctly published, it renders the participant's video or a user avatar if no video is to be shown. If you want to use a lower-level component, you can see the VideoRenderer as well.
It only displays the video and doesn't add any other UI elements. The video is lazily loaded, and only requested from the video infrastructure if you're actually displaying it. So if you have a video call with 200 participants, and you show only 10 of them, you'll only receive video for 10 participants. This is how software like Zoom and Google Meet make large calls work.
FloatingParticipantVideo renders a draggable display of your own video.
Step 6 - A Full Video Calling UI
Confused about "Step 6 - A Full Video Calling UI"?
Let us know how we can improve our documentation:
The above example showed how to use the call state object and Compose to build a basic video UI. For a production version of calling you'd want a few more UI elements:
- Indicators of when someone is speaking
- Quality of their network
- Layout support for >2 participants
- Labels for the participant names
- Call header and controls
Stream ships with several Compose components to make this easy. You can customize the components with theming, arguments and swapping parts of them. This is convenient if you want to quickly build a production ready calling experience for your app (and if you need more flexibility, many customers use the above low level approach to build a UI from scratch).
To render a full calling UI, we'll leverage the CallContent component. This includes sensible defaults for a call header, video grid, call controls, picture-in-picture, and everything that you need to build a video call screen.
Open MainActivity.kt
, and update the code inside of VideoTheme
to use the CallContent
.
The code will be a lot smaller than before since all UI logic is handled in the CallContent
:
The result will be:
When you now run your app, you'll see a more polished video UI. It supports reactions, screen sharing, active speaker detection, network quality indicators, etc. The most commonly used UI components are:
- VideoRenderer: For rendering video and automatically requesting video tracks when needed. Most of the Video components are built on top of this.
- ParticipantVideo: The participant's video + some UI elements for network quality, reactions, speaking etc.
- ParticipantsGrid: A grid of participant video elements.
- FloatingParticipantVideo: A draggable version of the participant video. Typically used for your own video.
- ControlActions: A set of buttons for controlling your call, such as changing audio and video states.
- RingingCallContent: UI for displaying incoming and outgoing calls.
The full list of UI components is available in the docs.
Step 7 - Customizing the UI
Confused about "Step 7 - Customizing the UI"?
Let us know how we can improve our documentation:
You can customize the UI by:
- Building your own UI components (the most flexible, build anything).
- Mixing and matching with Stream's UI Components (speeds up how quickly you can build common video UIs).
- Theming (basic customization of colors, fonts, etc.).
The example below shows how to swap out the call controls for your own controls:
Stream's Video SDK provides fully polished UI components, allowing you to build a video call quickly and customize them. As you've seen before, you can implement a full complete video call screen with CallContent
composable in Jetpack Compose. The CallContent
composable consists of three major parts:
appBarContent
: Content is shown that calls information or additional actions.controlsContent
: Content is shown that allows users to trigger different actions to control a joined call.videoContent
: Content shown to be rendered when we're connected to a call successfully.
Theming gives you control over the colors and fonts.
Recap
Confused about "Recap"?
Let us know how we can improve our documentation:
Please let us know if you ran into any issues while building this video calling app with Compose. Our team is also happy to review your UI designs and offer recommendations on how to achieve them with our components.
To recap what we've learned about Android video calling:
- You set up a call: (
val call = client.call("default", "123")
) - The call type (
"default"
in the above case) controls which features are enabled and how permissions are setup - When you join a call, real-time communication is setup for audio & video calling: (
call.join()
) StateFlow
objects incall.state
andcall.state.participants
make it easy to build your own UIVideoRenderer
is the low-level component that renders video
We've used Stream's Video Calling API in this tutorial, which means calls run on a global edge network of video servers. Being closer to your users improves the latency and reliability of calls. The Compose SDK enables you to build in-app video calling, audio rooms, and live streaming in days.
We hope you've enjoyed this tutorial. Please feel free to contact us if you have any suggestions or questions.
Samples
Confused about "Samples"?
Let us know how we can improve our documentation:
If you're interested in learning more use cases of Video SDK with codes, check out the GitHub repositories below:
- Android Video Chat: Android Video Chat demonstrates a real-time video chat application by utilizing Stream Chat & Video SDKs.
- Android Video Samples: Provides a collection of samples that utilize modern Android tech stacks and Stream Video SDK for Kotlin and Compose.
- WhatsApp Clone Compose: WhatsApp clone project demonstrates modern Android development built with Jetpack Compose and Stream Chat/Video SDK for Compose.
- Twitch Clone Compose: Twitch clone project demonstrates modern Android development built with Jetpack Compose and Stream Chat/Video SDK for Compose.
- Meeting Room Compose: A real-time meeting room app built with Jetpack Compose to demonstrate video communications.
- Audio Only Demo: A sample implementation of an audio-only caller application with Android Video SDK.
Final Thoughts
In this video app tutorial we built a fully functioning Android messaging app with our Android SDK component library. We also showed how easy it is to customize the behavior and the style of the Android video app components with minimal code changes.
Both the video SDK for Android and the API have plenty more features available to support more advanced use-cases.
Give us Feedback!
Did you find this tutorial helpful in getting you up and running with Android for adding video to your project? Either good or bad, we’re looking for your honest feedback so we can improve.