Introduction to Android Development
Remote communication has become a pivotal part of our interactions post-pandemic, and without a doubt, it will continue to play a significant role in our future. Today's mobile applications frequently include functionalities for 1on1 video calls and video chats, but creating these features is extremely complex and time-consuming. This is where VideoSDK steps in. VideoSDK provides developers with simple-to-use, highly customizable, and widely compatible APIs to embed real-time video, voice, and interactive functionalities into their applications. With VideoSDK, developers can easily integrate 1on1 video call capabilities, even on platforms like Android, without the need to develop the technology or the underlying infrastructure for real-time engagement themselves. This makes adding video calling on Android and other platforms straightforward and efficient.
Goals
By the end of this blog, you will be able to:
- Understand what VideoSDK is.
- Create a Video SDK account and generate a token.
- Create a 1-to-1 video chat app using Android and Video SDK.
What is VideoSDK?
VideoSDK is a versatile platform that empowers developers across the USA & India to create rich in-app experiences by embedding real-time video, voice, recording, live streaming, and messaging functionalities. Available in JavaScript, ReactJS, React-Native, iOS, Android, and Flutter, VideoSDK allows for seamless integration into diverse application frameworks. Additionally, VideoSDK offers a pre-built SDK designed for rapid deployment, enabling developers in the US & India to integrate sophisticated real-time communication features with their applications in just 10 minutes.
✨ Awesome, right?
Let's create a 1-to-1 video calling in Kotlin Android using the VideoSDK. But first, we need to create a VideoSDK account and generate a token.
Set up your VideoSDK account and generate a token.
- A Video SDK Token (Dashboard > Api-Key) (Video Tutorial)
?️ Prerequisites & Setup of the project
Before proceeding, ensure that your development environment meets the following requirements:
- Java Development Kit.
- Android Studio 3.0 or later.
- Android SDK API Level 21 or higher.
- A mobile device that runs Android 5.0 or later.
Create a new project
- Let’s start by creating a new project. In Android Studio, create a Phone and Tablet Android project with an Empty Activity.
- The next step is to provide a name. We will name it as OneToOneDemo.
Integrating VideoSDK into Your Android App
- Add the repository to the project's
settings.gradle
file.
dependencyResolutionManagement{
repositories {
// ...
google()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
}
- Add the following dependency to your app's
build.gradle
.
dependencies {
implementation 'live.videosdk:rtc-android-sdk:0.1.13'
// library to perform Network call to generate a meeting id
implementation 'com.amitshekhar.android:android-networking:1.0.2'
// other app dependencies
}
If your project has setandroid.useAndroidX=true
, then setandroid.enableJetifier=true
in thegradle.properties
file to migrate your project to AndroidX and avoid duplicate class conflict.
- Add permissions to your project
In /app/Manifests/AndroidManifest.xml
, add the following permissions after </application>
.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
Build 1on1 Video Call App on Android
STEP 1: Android Video Chat SDK Structure of Project
We will create two screens. The first screen is Joining screen
, which allows the user to create/join the meeting, and the other is Meeting screen
, which will show participants a Whatsapp-like view.
Our project structure would look like this.
app
├── java
│ ├── packagename
│ ├── JoinActivity
│ ├── MeetingActivity
├── res
│ ├── layout
│ │ ├── activity_join.xml
│ │ ├── activity_meeting.xml
You have to set JoinActivity
as Launcher activity.
- Creating Joining Screen
Create a new Activity named JoinActivity
STEP 2:Android Video Chat SDK Creating UI for Joining Screen
The Joining screen will include:
- Create Button - This button will create a new meeting for you.
- TextField for Meeting ID - This text field will contain the meeting ID you want to join.
- Join Button - This button will join the meeting with
meetingId
you provided.
In /app/res/layout/activity_join.xml
file, replace the content with the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".JoinActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStart="0dp"
android:background="?attr/colorPrimary"
app:titleTextColor="@color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/btnCreateMeeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Create Meeting" />
<TextView
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OR" />
<com.google.android.material.textfield.TextInputLayout style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:hint="Enter Meeting ID">
<EditText
android:id="@+id/etMeetingId"
android:layout_width="250dp"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnJoinMeeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Meeting" />
</LinearLayout>
</LinearLayout>
STEP 3: Android Video Chat SDK Integration of Create Meeting API
- Create a field
sampleToken
inJoinActivity
which will hold the generated token from the Video SDK dashboard. This token will be used in the Video SDK config as well as generating meetingId.
class JoinActivity : AppCompatActivity() {
//Replace with the token you generated from the Video SDK Dashboard
private var sampleToken = ""
override fun onCreate(savedInstanceState: Bundle?) {
//...
}
}
- On the Join Button
onClick
event, we will navigate toMeetingActivity
with token and meetingId.
class JoinActivity : AppCompatActivity() {
//Replace with the token you generated from the VideoSDK Dashboard
private var sampleToken = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_join)
val btnCreate = findViewById<Button>(R.id.btnCreateMeeting)
val btnJoin = findViewById<Button>(R.id.btnJoinMeeting)
val etMeetingId = findViewById<EditText>(R.id.etMeetingId)
//set title
val toolbar = findViewById<Toolbar>(R.id.material_toolbar)
toolbar.title = "OneToOneDemo"
setSupportActionBar(toolbar)
btnCreate.setOnClickListener { v: View? ->
// we will explore this method in the next step
createMeeting(sampleToken)
}
btnJoin.setOnClickListener { v: View? ->
val intent = Intent(this@JoinActivity, MeetingActivity::class.java)
intent.putExtra("token", sampleToken)
intent.putExtra("meetingId", etMeetingId.text.toString())
startActivity(intent)
}
}
private fun createMeeting(token: String) {
}
}
- For the Create Button, under
createMeeting
method we will generate meetingId by calling API and navigating toMeetingActivity
with token and generated meetingId.
class JoinActivity : AppCompatActivity() {
//...onCreate
private fun createMeeting(token: String) {
// we will make an API call to VideoSDK Server to get a roomId
AndroidNetworking.post("https://api.videosdk.live/v2/rooms")
.addHeaders("Authorization", token) //we will pass the token in the Headers
.build()
.getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) {
try {
// response will contain `roomId`
val meetingId = response.getString("roomId")
// starting the MeetingActivity with received roomId and our sampleToken
val intent = Intent(this@JoinActivity, MeetingActivity::class.java)
intent.putExtra("token", sampleToken)
intent.putExtra("meetingId", meetingId)
startActivity(intent)
} catch (e: JSONException) {
e.printStackTrace()
}
}
override fun onError(anError: ANError) {
anError.printStackTrace()
Toast.makeText(
this@JoinActivity, anError.message,
Toast.LENGTH_SHORT
).show()
}
})
}
}
- Our App is completely based on audio and video commutation, that's why we need to ask for runtime permissions
RECORD_AUDIO
andCAMERA
. So, we will implement permission logic onJoinActivity
.
class JoinActivity : AppCompatActivity() {
companion object {
private const val PERMISSION_REQ_ID = 22
private val REQUESTED_PERMISSIONS = arrayOf(
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
)
}
private fun checkSelfPermission(permission: String, requestCode: Int): Boolean {
if (ContextCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode)
return false
}
return true
}
override fun onCreate(savedInstanceState: Bundle?) {
//... button listeneres
checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID)
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)
}
}
You will getUnresolved reference: MeetingActivity
error, but don't worry. It will be solved automatically once you createMeetingActivity
.
- The Joining screen is now complete, and it is time to create the participant's view in the Meeting screen. The Joining screen will look like this:
Creating Meeting Screen
Create a new Activity named MeetingActivity
.
STEP 4: Video Chat Android SDK Creating the UI for Meeting Screen
In /app/res/layout/activity_meeting.xml
file, replace the content with the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:gravity="center"
android:orientation="vertical"
tools:context=".MeetingActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/black"
app:contentInsetStart="0dp"
app:titleTextColor="@color/white">
<LinearLayout
android:id="@+id/meetingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txtMeetingId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-medium"
android:textColor="@color/white"
android:textFontWeight="600"
android:textSize="16sp" />
<ImageButton
android:id="@+id/btnCopyContent"
android:layout_width="22dp"
android:layout_height="22sp"
android:layout_marginLeft="7dp"
android:layout_toRightOf="@+id/txtMeetingId"
android:backgroundTint="@color/black"
android:src="@drawable/ic_outline_content_copy_24" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="10dp">
<ImageButton
android:id="@+id/btnSwitchCameraMode"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/black"
android:contentDescription="Switch Camera mode"
android:src="@drawable/ic_baseline_flip_camera_android_24" />
</LinearLayout>
</com.google.android.material.appbar.MaterialToolbar>
<FrameLayout
android:id="@+id/participants_frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/black">
<androidx.cardview.widget.CardView
android:id="@+id/ParticipantCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="12dp"
android:layout_marginTop="3dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="3dp"
android:backgroundTint="#2B3034"
android:visibility="gone"
app:cardCornerRadius="8dp"
app:strokeColor="#2B3034">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:src="@drawable/ic_baseline_person_24" />
<live.videosdk.rtc.android.VideoView
android:id="@+id/participantView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</androidx.cardview.widget.CardView>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<androidx.cardview.widget.CardView
android:id="@+id/LocalCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="12dp"
android:layout_marginTop="3dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="3dp"
android:backgroundTint="#1A1C22"
app:cardCornerRadius="8dp"
app:strokeColor="#1A1C22">
<ImageView
android:id="@+id/localParticipant_img"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:src="@drawable/ic_baseline_person_24" />
<live.videosdk.rtc.android.VideoView
android:id="@+id/localView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</androidx.cardview.widget.CardView>
</FrameLayout>
<!-- add bottombar here-->
</LinearLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:backgroundTint="@color/black"
android:gravity="center_horizontal"
android:paddingVertical="5dp"
tools:ignore="BottomAppBar">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnLeave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Leave Meeting"
android:src="@drawable/ic_end_call"
app:backgroundTint="#FF5D5D"
app:fabSize="normal"
app:tint="@color/white" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnMic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="90dp"
android:layout_toEndOf="@+id/btnLeave"
android:contentDescription="Toggle Mic"
android:src="@drawable/ic_mic_off"
app:backgroundTint="@color/white"
app:borderWidth="1dp"
app:fabSize="normal" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnWebcam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="90dp"
android:layout_toEndOf="@+id/btnMic"
android:backgroundTint="@color/white"
android:contentDescription="Toggle Camera"
android:src="@drawable/ic_video_camera_off"
app:backgroundTint="@color/white"
app:borderWidth="1dp"
app:fabSize="normal" />
</RelativeLayout>
</com.google.android.material.bottomappbar.BottomAppBar>
Copy required icons from here and paste in your project's `res/drawable
res/drawable
folder.
STEP 5: Video Chat Android SDK Initializing the Meeting
After getting the token and meetingId from JoinActivity
we need to,
- Initialize VideoSDK
- Configure VideoSDK with the token.
- Initialize the meeting with required params such as
meetingId
,participantName
,micEnabled
,webcamEnabled
,participantId
and map ofCustomStreamTrack
. - Join the room with
meeting.join()
method.
class MeetingActivity : AppCompatActivity() {
private var meeting: Meeting? = null
private var micEnabled = true
private var webcamEnabled = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
//
val toolbar = findViewById<Toolbar>(R.id.material_toolbar)
toolbar.title = ""
setSupportActionBar(toolbar)
//
val token = intent.getStringExtra("token")
val meetingId = intent.getStringExtra("meetingId")
// set participant name
val localParticipantName = "Alex"
// Initialize VideoSDK
VideoSDK.initialize(applicationContext)
// pass the token generated from api server
VideoSDK.config(token)
// create a new meeting instance
meeting = VideoSDK.initMeeting(
this@MeetingActivity, meetingId, localParticipantName,
micEnabled, webcamEnabled, null, null
)
// join the meeting
meeting?.join()
//
val textMeetingId = findViewById<TextView>(R.id.txtMeetingId)
textMeetingId.text = meetingId
// copy meetingId to clipboard
(findViewById<View>(R.id.btnCopyContent) as ImageButton).setOnClickListener {
if (meetingId != null) {
copyTextToClipboard(meetingId)
}
}
}
private fun copyTextToClipboard(text: String) {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Copied text", text)
clipboard.setPrimaryClip(clip)
Toast.makeText(this@MeetingActivity, "Copied to clipboard!", Toast.LENGTH_SHORT).show()
}
}
? STEP 6: Video Chat Android SDK Handle Local Participant Media
We need to implement clicks for the following Views
:
- Mic Button
- Webcam Button
- Switch Camera Button
- Leave Button
Add the following implementation:
class MeetingActivity : AppCompatActivity() {
private var btnWebcam: FloatingActionButton? = null
private var btnMic: FloatingActionButton? = null
private var btnLeave: FloatingActionButton? = null
private var btnSwitchCameraMode: ImageButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
//
btnLeave = findViewById(R.id.btnLeave)
btnSwitchCameraMode = findViewById(R.id.btnSwitchCameraMode)
btnMic = findViewById(R.id.btnMic)
btnWebcam = findViewById(R.id.btnWebcam)
//...
// actions
setActionListeners()
}
private fun setActionListeners() {
// Toggle mic
btnMic!!.setOnClickListener { toggleMic() }
// Toggle webcam
btnWebcam!!.setOnClickListener { toggleWebCam() }
// Leave meeting
btnLeave!!.setOnClickListener {
// this will make the local participant leave the meeting
meeting!!.leave()
}
// Switch camera
btnSwitchCameraMode!!.setOnClickListener {
//a participant can change stream from front/rear camera during the meeting.
meeting!!.changeWebcam()
}
}
}
private fun toggleMic() {
if (micEnabled) {
// this will mute the local participant's mic
meeting!!.muteMic()
} else {
// this will unmute the local participant's mic
meeting!!.unmuteMic()
}
micEnabled = !micEnabled
// change mic icon according to micEnable status
toggleMicIcon()
}
@SuppressLint("ResourceType")
private fun toggleMicIcon() {
if (micEnabled) {
btnMic!!.setImageResource(R.drawable.ic_mic_on)
btnMic!!.setColorFilter(Color.WHITE)
var buttonDrawable = btnMic!!.background
buttonDrawable = DrawableCompat.wrap(buttonDrawable!!)
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT)
btnMic!!.background = buttonDrawable
} else {
btnMic!!.setImageResource(R.drawable.ic_mic_off)
btnMic!!.setColorFilter(Color.BLACK)
var buttonDrawable = btnMic!!.background
buttonDrawable = DrawableCompat.wrap(buttonDrawable!!)
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE)
btnMic!!.background = buttonDrawable
}
}
private fun toggleWebCam() {
if (webcamEnabled) {
// this will disable the local participant webcam
meeting!!.disableWebcam()
} else {
// this will enable the local participant webcam
meeting!!.enableWebcam()
}
webcamEnabled = !webcamEnabled
// change webCam icon according to webcamEnabled status
toggleWebcamIcon()
}
@SuppressLint("ResourceType")
private fun toggleWebcamIcon() {
if (webcamEnabled) {
btnWebcam!!.setImageResource(R.drawable.ic_video_camera)
btnWebcam!!.setColorFilter(Color.WHITE)
var buttonDrawable = btnWebcam!!.background
buttonDrawable = DrawableCompat.wrap(buttonDrawable!!)
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT)
btnWebcam!!.background = buttonDrawable
} else {
btnWebcam!!.setImageResource(R.drawable.ic_video_camera_off)
btnWebcam!!.setColorFilter(Color.BLACK)
var buttonDrawable = btnWebcam!!.background
buttonDrawable = DrawableCompat.wrap(buttonDrawable!!)
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE)
btnWebcam!!.background = buttonDrawable
}
}
STEP 7: Setting up Local participant view
To set up participant view, we have to implement all the methods of ParticipantEventListener
abstract Class and add the listener to Participant
class using the addEventListener()
method of Participant
Class. ParticipantEventListener
class has two methods :
onStreamEnabled
- Whenever any participant enables mic/webcam in the meeting,onStreamEnabled
the event will trigger and returnStream
.onStreamDisabled
- Whenever any participant disables mic/webcam in the meeting,onStreamDisabled
the event will trigger and returnStream
.
class MeetingActivity : AppCompatActivity() {
private var localView: VideoView? = null
private var participantView: VideoView? = null
private var localCard: CardView? = null
private var participantCard: CardView? = null
private var localParticipantImg: ImageView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
//...
localCard = findViewById(R.id.LocalCard)
participantCard = findViewById(R.id.ParticipantCard)
localView = findViewById(R.id.localView)
participantView = findViewById(R.id.participantView) localParticipantImg = findViewById(R.id.localParticipant_img)
//...
// setup local participant view
setLocalListeners()
}
private fun setLocalListeners() {
meeting!!.localParticipant
.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
val track = stream.track as VideoTrack
localView!!.visibility = View.VISIBLE
localView!!.addTrack(track)
localView!!.setZOrderMediaOverlay(true)
(localCard as View?)!!.bringToFront()
}
}
override fun onStreamDisabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
localView!!.removeTrack()
localView!!.visibility = View.GONE
}
}
})
}
}
STEP 8: Setting up Remote participant view
private val participantEventListener: ParticipantEventListener =
object : ParticipantEventListener() {
// trigger when participant enabled mic/webcam
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
localView!!.setZOrderMediaOverlay(true)
(localCard as View?)!!.bringToFront()
val track = stream.track as VideoTrack
participantView!!.visibility = View.VISIBLE
participantView!!.addTrack(track)
}
}
// trigger when participant disabled mic/webcam
override fun onStreamDisabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
participantView!!.removeTrack()
participantView!!.visibility = View.GONE
}
}
}
STEP 9: Handle meeting events & manage participant's view
- Add
MeetingEventListener
for listening events such as Meeting Join/Left and Participant Join/Left.
class MeetingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
//...
// handle meeting events
meeting!!.addEventListener(meetingEventListener)
}
private val meetingEventListener: MeetingEventListener = object : MeetingEventListener() {
override fun onMeetingJoined() {
// change mic,webCam icon after meeting successfully joined
toggleMicIcon()
toggleWebcamIcon()
}
override fun onMeetingLeft() {
if (!isDestroyed) {
val intent = Intent(this@MeetingActivity, JoinActivity::class.java)
startActivity(intent)
finish()
}
}
override fun onParticipantJoined(participant: Participant) {
// Display local participant as miniView when other participant joined
changeLocalParticipantView(true)
Toast.makeText(
this@MeetingActivity, participant.displayName + " joined",
Toast.LENGTH_SHORT
).show()
participant.addEventListener(participantEventListener)
}
override fun onParticipantLeft(participant: Participant) {
// Display local participant as largeView when other participant left
changeLocalParticipantView(false)
Toast.makeText(
this@MeetingActivity, participant.displayName + " left",
Toast.LENGTH_SHORT
).show()
}
}
}
changeLocalParticipantView(isMiniView: Boolean)
function handles whether the video of a local participant is displayed as a MiniView or a LargeView.- If the meeting has only one participant (local participant), then the local participant is displayed as LargeView.
- When another participant (other than the local participant) joins,
changeLocalParticipantView(true)
is called. As a result, the local participant is shown as MiniView, while the other participant is shown as LargeView.
private fun changeLocalParticipantView(isMiniView: Boolean) {
if (isMiniView) {
// show localCard as miniView
localCard!!.layoutParams =
FrameLayout.LayoutParams(300, 430, Gravity.RIGHT or Gravity.BOTTOM)
val cardViewMarginParams = localCard!!.layoutParams as MarginLayoutParams
cardViewMarginParams.setMargins(30, 0, 60, 40)
localCard!!.requestLayout()
// set height-width of localParticipant_img
localParticipantImg!!.layoutParams = FrameLayout.LayoutParams(150, 150, Gravity.CENTER)
(localCard as View?)!!.bringToFront()
participantCard!!.visibility = View.VISIBLE
} else {
// show localCard as largeView
localCard!!.layoutParams =
FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
val cardViewMarginParams = localCard!!.layoutParams as MarginLayoutParams
cardViewMarginParams.setMargins(30, 5, 30, 30)
localCard!!.requestLayout()
// set height-width of localParticipant_img
localParticipantImg!!.layoutParams = FrameLayout.LayoutParams(400, 400, Gravity.CENTER)
participantCard!!.visibility = View.GONE
}
}
STEP 10: Destroying everything
We need to release resources when the app is closed and is no longer being used. Override the onDestroy
with the following code:
override fun onDestroy() {
if (meeting != null) {
meeting!!.removeAllListeners()
meeting!!.localParticipant.removeAllListeners()
meeting!!.leave()
meeting = null
}
if (participantView != null) {
participantView!!.visibility = View.GONE
participantView!!.releaseSurfaceViewRenderer()
}
if (localView != null) {
localView!!.visibility = View.GONE
localView!!.releaseSurfaceViewRenderer()
}
super.onDestroy()
}
This is how the meeting screen will seem with two participants.
java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
If you face this error at Runtime include these lines intheme.xml
file.
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
1-to-1 Video Chat App Demo
Tadaa!! Our app is ready. Easy, right?
I hope you enjoyed following along and collaborating on the development of a 1-to-1 video chat Android app using the Video SDK.
Install and run the app on two different devices and make sure that they are connected to the internet. You should expect it to work as shown in the video below:
This app only supports 2 participant,it does not manage more than 2 participants. If you want to handle more than 2 participants then checkout our Group chat example here.
Conclusion
In this blog, we learned what VideoSDK is, how to obtain an access token from the VideoSDK Dashboard, and how to make a video call on Android VideoSDK. Go ahead and create advanced features like screen-sharing, chat, and others. Browse Our Documentation.
To see the full implementation of the app, check out the GitHub repository: https://github.com/videosdk-live/videosdk-rtc-android-kotlin-sdk-example/tree/one-to-one-demo
If you have any questions or comments, I invite you to Join the Video SDK Developer Discord community.
Resources
- Get Started with Android Documentation
- Build an Android Video Calling App using Android Studio and Video SDK
- Build a React Native Android Video Calling App with ?Callkeep using ? Firebase and Video SDK
- Build a Flutter Video Calling App with Video SDK