Skip to main content
Version: 0.1.x

Quick Start for Conference in Android

VideoSDK enables you to embed the video calling feature into your Android application in minutes.

In this quickstart, we are going to explore group calling feature of Video SDK. We will go through step by step guide of integrating video calling with Android Video SDK.

This guide will get you running with the VideoSDK video & audio calling in minutes.

Prerequisites

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.
important

One should have a VideoSDK account to generate token. Visit VideoSDK dashboard to generate token

Getting Started with the Code!

Follow the steps to create the environment necessary to add video calls into your app. Also you can find the code sample for quickstart here.

Create new Android Project

For a new project in Android Studio, create a Phone and Tablet Android project with an Empty Activity.

VideoSDK Android Quick Start New Project

caution

After creating the project, Android Studio automatically starts gradle sync. Ensure that the sync succeeds before you continue.

Integrate Video SDK

settings.gradle
dependencyResolutionManagement{
repositories {
// ...
google()
mavenCentral()
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
}
note

You can use imports with Maven Central after rtc-android-sdk version 0.1.12.

Whether on Maven or Jitpack, the same version numbers always refer to the same SDK.

  • Add the following dependency in your app's app/build.gradle.
app/build.gradle
dependencies {
implementation 'live.videosdk:rtc-android-sdk:0.1.37'

// library to perform Network call to generate a meeting id
implementation 'com.amitshekhar.android:android-networking:1.0.2'

// other app dependencies
}
important

Android SDK compatible with armeabi-v7a, arm64-v8a, x86_64 architectures. If you want to run the application in an emulator, choose ABI x86_64 when creating a device.

Add permissions into your project

  • In /app/Manifests/AndroidManifest.xml, add the following permissions after </application>.
AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
note

If your project has set android.useAndroidX=true, then set android.enableJetifier=true in the gradle.properties file to migrate your project to AndroidX and avoid duplicate class conflict.

Structure of the project

Your project structure should look like this.

Project Structure
   app
├── java
│ ├── packagename
│ ├── JoinActivity
│ ├── MainApplication
│ ├── MeetingActivity
│ ├── ParticipantAdapter
├── res
│ ├── layout
│ │ ├── activity_join.xml
│ │ ├── activity_meeting.xml
│ │ ├── item_remote_peer.xml
note

You have to set JoinActivity as Launcher activity.

App Architecture

Step 1: Initialize VideoSDK

  1. Create MainApplication class which will extend the android.app.Application.
MainApplication.kt
import live.videosdk.rtc.android.VideoSDK

class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
VideoSDK.initialize(applicationContext)
}
}
  1. Add MainApplication to AndroidManifest.xml
AndroidManifest.xml
<application
android:name=".MainApplication" >
<!-- ... -->
</application>

Step 2: Creating Joining Screen

Create a new Activity named JoinActivity.

Creating UI

The Joining screen will include :

  1. Create Button - This button will create a new meeting for you.
  2. TextField for Meeting Id - This text field will contain the meeting Id you want to join.
  3. 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.

activity_join.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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">

<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>

Integration of Create Meeting API

  1. Create field sampleToken in JoinActivity which will hold the generated token from the VideoSDK dashboard. This token will use in VideoSDK config as well as in generating meetingId.
JoinActivity.kt
class JoinActivity : AppCompatActivity() {

//Replace with the token you generated from the VideoSDK Dashboard
private var sampleToken = ""

override fun onCreate(savedInstanceState: Bundle?) {
//...
}
}
  1. On Join Button onClick events, we will naviagte to MeetingActivity with token and meetingId.
JoinActivity.kt
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)

btnCreate.setOnClickListener { v: View? ->
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) {
// we will explore this method in the next step
}
}
  1. For Create Button, under createMeeting method we will generate meetingId by calling API and navigate to MeetingActivity with token and generated meetingId.
JoinActivity.kt
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()
}
})
}
}
note

Don't confuse with Room and Meeting keyword, both are same thing 😃

  1. Our App is completely based on audio and video commutation, that's why we need to ask for runtime permissions RECORD_AUDIO and CAMERA. So, we will implement permission logic on JoinActivity.
JoinActivity.kt
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)
}
}

Output

VideoSDK Android Quick Start joining Screen

Step 3: Creating Meeting Screen

Create a new Activity named MeetingActivity.

Creating the UI for Meeting Screen

In /app/res/layout/activity_meeting.xml file, replace the content with the following.

activty_meeting.xml
<?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=".MeetingActivity">

<TextView
android:id="@+id/tvMeetingId"
style="@style/TextAppearance.AppCompat.Display1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Meeting Id" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvParticipants"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<Button
android:id="@+id/btnMic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:text="Mic"/>

<Button
android:id="@+id/btnLeave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginHorizontal="8dp"
android:text="Leave"/>

<Button
android:id="@+id/btnWebcam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:text="Webcam" />

</LinearLayout>

</LinearLayout>

Initializing the Meeting

After getting token and meetigId from JoinActivity,

  1. Configure VideoSDK with token.
  2. Initialize the meeting with required params such as meetingId, participantName, micEnabled, webcamEnabled and more.
  3. Add MeetingEventListener for listening events such as Meeting Join/Left and Participant Join/Left.
  4. Join the room with meeting.join() method.
MeetingActivity.kt
class MeetingActivity : AppCompatActivity() {
// declare the variables we will be using to handle the meeting
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 token = intent.getStringExtra("token")
val meetingId = intent.getStringExtra("meetingId")
val participantName = "John Doe"

// 1. Configuration VideoSDK with Token
VideoSDK.config(token)

// 2. Initialize VideoSDK Meeting
meeting = VideoSDK.initMeeting(
this@MeetingActivity, meetingId, participantName,
micEnabled, webcamEnabled, null, null, false, null, null)

// 3. Add event listener for listening upcoming events
meeting!!.addEventListener(meetingEventListener)

//4. Join VideoSDK Meeting
meeting!!.join()

(findViewById<View>(R.id.tvMeetingId) as TextView).text = meetingId
}

// creating the MeetingEventListener
private val meetingEventListener: MeetingEventListener = object : MeetingEventListener() {
override fun onMeetingJoined() {
Log.d("#meeting", "onMeetingJoined()")
}

override fun onMeetingLeft() {
Log.d("#meeting", "onMeetingLeft()")
meeting = null
if (!isDestroyed) finish()
}

override fun onParticipantJoined(participant: Participant) {
Toast.makeText(
this@MeetingActivity, participant.displayName + " joined",
Toast.LENGTH_SHORT
).show()
}

override fun onParticipantLeft(participant: Participant) {
Toast.makeText(
this@MeetingActivity, participant.displayName + " left",
Toast.LENGTH_SHORT
).show()
}
}
}

Step 4: Handle Local Participant Media

After successfully enter into the meeting, it's time to enable/disable local participant(You) webcam and mic, for that we will use Meeting class method enableWebcam / disableWebcam for camera and muteMic / unmuteMic for mic.

MeetingActivity.kt
class MeetingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
//...Meeting Setup is Here

// actions
setActionListeners()
}

private fun setActionListeners() {
// toggle mic
findViewById<View>(R.id.btnMic).setOnClickListener { view: View? ->
if (micEnabled) {
// this will mute the local participant's mic
meeting!!.muteMic()
Toast.makeText(this@MeetingActivity, "Mic Muted", Toast.LENGTH_SHORT).show()
} else {
// this will unmute the local participant's mic
meeting!!.unmuteMic()
Toast.makeText(this@MeetingActivity, "Mic Enabled", Toast.LENGTH_SHORT).show()
}
micEnabled=!micEnabled
}

// toggle webcam
findViewById<View>(R.id.btnWebcam).setOnClickListener { view: View? ->
if (webcamEnabled) {
// this will disable the local participant webcam
meeting!!.disableWebcam()
Toast.makeText(this@MeetingActivity, "Webcam Disabled", Toast.LENGTH_SHORT).show()
} else {
// this will enable the local participant webcam
meeting!!.enableWebcam()
Toast.makeText(this@MeetingActivity, "Webcam Enabled", Toast.LENGTH_SHORT).show()
}
webcamEnabled=!webcamEnabled
}

// leave meeting
findViewById<View>(R.id.btnLeave).setOnClickListener { view: View? ->
// this will make the local participant leave the meeting
meeting!!.leave()
}
}
}

Output

Step 5: Handling the Participants View

We will be showing the list of participant in a RecyclerView.

info
  • Here the participant's video is displayed using VideoView, but you may also use SurfaceViewRender for the same.
  • For VideoView, SDK version should be 0.1.13 or higher.
  • To know more about VideoView, please visit here
  1. Create a new layout for the participant view named item_remote_peer.xml in the res/layout folder.
item_remote_peer.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="200dp"
android:background="@color/cardview_dark_background"
tools:layout_height="200dp">

<live.videosdk.rtc.android.VideoView
android:id="@+id/participantView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#99000000"
android:orientation="horizontal">

<TextView
android:id="@+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="4dp"
android:textColor="@color/white" />

</LinearLayout>

</FrameLayout>
  1. Create a recycler view adapter named ParticipantAdapter which will show the participant list. Create PeerViewHolder in the adapter which will extend RecyclerView.ViewHolder.
ParticipantAdapter.kt
class ParticipantAdapter(meeting: Meeting) : RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PeerViewHolder {
return PeerViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_remote_peer, parent, false)
)
}

override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
}

override fun getItemCount(): Int {
return 0
}

class PeerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
// 'VideoView' to show Video Stream
var participantView: VideoView
var tvName: TextView

init {
tvName = view.findViewById(R.id.tvName)
participantView = view.findViewById(R.id.participantView)
}
}
}
  1. Now, we will render a list of Participant for the meeting. We will initialize this list in the constructor of the ParticipantAdapter
ParticipantAdapter.kt
class ParticipantAdapter(meeting: Meeting) :
RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {

// creating a empty list which will store all participants
private val participants: MutableList<Participant> = ArrayList()

init {
// adding the local participant(You) to the list
participants.add(meeting.localParticipant)

// adding Meeting Event listener to get the participant join/leave event in the meeting.
meeting.addEventListener(object : MeetingEventListener() {
override fun onParticipantJoined(participant: Participant) {
// add participant to the list
participants.add(participant)
notifyItemInserted(participants.size - 1)
}

override fun onParticipantLeft(participant: Participant) {
var pos = -1
for (i in participants.indices) {
if (participants[i].id == participant.id) {
pos = i
break
}
}
// remove participant from the list
participants.remove(participant)
if (pos >= 0) {
notifyItemRemoved(pos)
}
}
})
}

// replace getItemCount() method with following.
// this method returns the size of total number of participants
override fun getItemCount(): Int {
return participants.size
}
//...
}
  1. We have listed our participants. Let's set up the view holder to display a participant video.
PartipantAdapter.kt
class ParticipantAdapter(meeting: Meeting) :
RecyclerView.Adapter<ParticipantAdapter.PeerViewHolder>() {

// replace onBindViewHolder() method with following.
override fun onBindViewHolder(holder: PeerViewHolder, position: Int) {
val participant = participants[position]

holder.tvName.text = participant.displayName

// adding the initial video stream for the participant into the 'VideoView'
for ((_, stream) in participant.streams) {
if (stream.kind.equals("video", ignoreCase = true)) {
holder.participantView.visibility = View.VISIBLE
val videoTrack = stream.track as VideoTrack
holder.participantView.addTrack(videoTrack)
break
}
}

// add Listener to the participant which will update start or stop the video stream of that participant
participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
holder.participantView.visibility = View.VISIBLE
val videoTrack = stream.track as VideoTrack
holder.participantView.addTrack(videoTrack)
}
}

override fun onStreamDisabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
holder.participantView.removeTrack()
holder.participantView.visibility = View.GONE
}
}
})
}
}
  1. Add this adapter to the MeetingActivity
MeetingActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
//Meeting Setup...
//...
val rvParticipants = findViewById<RecyclerView>(R.id.rvParticipants)
rvParticipants.layoutManager = GridLayoutManager(this, 2)
rvParticipants.adapter = ParticipantAdapter(meeting!!)
}
tip

Stuck anywhere? Check out this example code on GitHub.

Final Output

We are done with implementation of customised video calling app in Android using Video SDK. To explore more features go through Basic and Advanced features.

tip

You can checkout the complete quick start example here.

Got a Question? Ask us on discord