Introduction
Remote communication has become the most important part of communication after the pandemic. It will likely play a significant role in the future too. Today's mobile applications often include voice or video chat functionality. But it's extremely complex and takes a lot of time to build. This is where VideoSDK comes into the picture.
VideoSDK is a platform that allows developers to create rich in-app experiences such as embedding real-time video, voice, real-time recording, live streaming, and real-time messaging.
VideoSDK is available for JavaScript, ReactJS, React-Native, IOS, Android, and Flutter to be integrated seamlessly. VideoSDK also provides a Pre-built SDK that enables the opportunity to integrate real-time communication with your application in just 10 minutes!
Let's create a 1 on 1 video chat/call app using VideoSDK. But first, we need to create a VideoSDK account and generate the token.
Requirement
First of all, Your development environment should meet 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.
Setup the project
STEP 1: Create a new project
- Let’s start by creating a new project. In Android Studio, create a new project with an Empty Activity.
- Then, provide a name. We will name it as OneToOneDemo.
STEP 2: Integrate VideoSDK
- Add the repository to
settings.gradle
file.
dependencyResolutionManagement{
repositories {
// ...
google()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
}
- Add the following dependencies in
build.gradle
file.
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.
STEP 3: 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" />
STEP 4: Getting started with the code!
(a) Structure of project
We'll create two screens. The first screen will be Joining screen
that allows users to create/join the meeting, and another one is Meeting screen
that will show participants like WhatsApp views.
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.
(b) Creating Joining Screen
Create a new Activity named JoinActivity
(c) Creating UI for Joining the Screen
The Joining screen will include :
- Create Button - Creates a new meeting.
- TextField for MeetingID - Contains the
meetingId
you want to join. - Join Button - Joins the meeting with the
meetingId
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>
(d) Integration of Create Meeting API
You need to create a field sampleToken
in JoinActivity
that holds the generated token from the VideoSDK dashboard. This token will be used in the VideoSDK config as well as generating meetingId.
public class JoinActivity extends AppCompatActivity {
//Replace with the token you generated from the VideoSDK Dashboard
private String sampleToken = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
}
}
On Join Button onClick
the event, it will navigate to MeetingActivity
with token and meetingId.
public class JoinActivity extends AppCompatActivity {
//Replace with the token you generated from the VideoSDK Dashboard
private String sampleToken ="";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join);
final Button btnCreate = findViewById(R.id.btnCreateMeeting);
final Button btnJoin = findViewById(R.id.btnJoinMeeting);
final EditText etMeetingId = findViewById(R.id.etMeetingId);
//set title
Toolbar toolbar = findViewById(R.id.material_toolbar);
toolbar.setTitle("OneToOneDemo");
setSupportActionBar(toolbar);
btnCreate.setOnClickListener(v -> {
// we will explore this method in the next step
createMeeting(sampleToken);
});
btnJoin.setOnClickListener(v -> {
Intent intent = new Intent(JoinActivity.this, MeetingActivity.class);
intent.putExtra("token", sampleToken);
intent.putExtra("meetingId", etMeetingId.getText().toString());
startActivity(intent);
});
}
private void createMeeting(String token) {
}
}
For the Create Button, under createMeeting
method we will generate meetingId
by calling API and navigating to MeetingActivity
with token and generated meetingId.
public class JoinActivity extends AppCompatActivity {
//...onCreate
private void createMeeting(String token) {
// 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(new JSONObjectRequestListener() {
@Override
public void onResponse(JSONObject response) {
try {
// response will contain `roomId`
final String meetingId = response.getString("roomId");
// starting the MeetingActivity with received roomId and our sampleToken
Intent intent = new Intent(JoinActivity.this, MeetingActivity.class);
intent.putExtra("token", sampleToken);
intent.putExtra("meetingId", meetingId);
startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(ANError anError) {
anError.printStackTrace();
Toast.makeText(JoinActivity.this, anError.getMessage(), 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
and CAMERA
. So, we will implement permission logic on JoinActivity
.
public class JoinActivity extends AppCompatActivity {
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
};
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
//... button listeneres
checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID);
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID);
}
}
You'll getUnresolved reference: MeetingActivity
error, but don't worry. It will be solved automatically once you createMeetingActivity
.
We're done with the Joining screen now, and it is time to create the participant's view in the Meeting screen.
STEP 5: Creating Meeting Screen
Create a new Activity named MeetingActivity
.
(a) Creating the UI for the 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.
(b) Initializing the Meeting
After getting the token and meetingId from JoinActivity
, we need to
- Step 1: Initialize VideoSDK
- Step 2: Configure VideoSDK with the token.
- Step 3: Initialize the meeting with required params such as
meetingId
,participantName
,micEnabled
,webcamEnabled
,participantId
and map ofCustomStreamTrack
. - Step 4: Join the room with
meeting.join()
method.
public class MeetingActivity extends AppCompatActivity {
private static Meeting meeting;
private boolean micEnabled = true;
private boolean webcamEnabled = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//
Toolbar toolbar = findViewById(R.id.material_toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
//
String token = getIntent().getStringExtra("token");
final String meetingId = getIntent().getStringExtra("meetingId");
// set participant name
String localParticipantName = "Alex";
// Initialize VideoSDK
VideoSDK.initialize(getApplicationContext());
// pass the token generated from api server
VideoSDK.config(token);
// create a new meeting instance
meeting = VideoSDK.initMeeting(
MeetingActivity.this, meetingId, localParticipantName,
micEnabled, webcamEnabled, null, null
);
// join the meeting
if (meeting != null) meeting.join();
//
TextView textMeetingId = findViewById(R.id.txtMeetingId);
textMeetingId.setText(meetingId);
// copy meetingId to clipboard
((ImageButton) findViewById(R.id.btnCopyContent)).setOnClickListener(v -> copyTextToClipboard(meetingId));
}
private void copyTextToClipboard(String text) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Copied text", text);
clipboard.setPrimaryClip(clip);
Toast.makeText(MeetingActivity.this, "Copied to clipboard!", Toast.LENGTH_SHORT).show();
}
}
STEP 6: 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:
public class MeetingActivity extends AppCompatActivity {
private FloatingActionButton btnWebcam, btnMic, btnLeave;
private ImageButton btnSwitchCameraMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//
btnMic = findViewById(R.id.btnMic);
btnWebcam = findViewById(R.id.btnWebcam);
btnLeave = findViewById(R.id.btnLeave);
btnSwitchCameraMode = findViewById(R.id.btnSwitchCameraMode);
//...
// actions
setActionListeners();
}
private void setActionListeners() {
// Toggle mic
btnMic.setOnClickListener(view -> toggleMic());
// Toggle webcam
btnWebcam.setOnClickListener(view -> toggleWebCam());
// Leave meeting
btnLeave.setOnClickListener(view -> {
// this will make the local participant leave the meeting
meeting.leave();
});
// Switch camera
btnSwitchCameraMode.setOnClickListener(view -> {
//a participant can change stream from front/rear camera during the meeting.
meeting.changeWebcam();
});
}
}
private void 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 void toggleMicIcon() {
if (micEnabled) {
btnMic.setImageResource(R.drawable.ic_mic_on);
btnMic.setColorFilter(Color.WHITE);
Drawable buttonDrawable = btnMic.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT);
btnMic.setBackground(buttonDrawable);
} else {
btnMic.setImageResource(R.drawable.ic_mic_off);
btnMic.setColorFilter(Color.BLACK);
Drawable buttonDrawable = btnMic.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE);
btnMic.setBackground(buttonDrawable);
}
}
private void 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 void toggleWebcamIcon() {
if (webcamEnabled) {
btnWebcam.setImageResource(R.drawable.ic_video_camera);
btnWebcam.setColorFilter(Color.WHITE);
Drawable buttonDrawable = btnWebcam.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT);
btnWebcam.setBackground(buttonDrawable);
} else {
btnWebcam.setImageResource(R.drawable.ic_video_camera_off);
btnWebcam.setColorFilter(Color.BLACK);
Drawable buttonDrawable = btnWebcam.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE);
btnWebcam.setBackground(buttonDrawable);
}
}
(a) Setting up Local participant view
To set up participant view, we have to implement all the methods of the ParticipantEventListener
Abstract Class and add the listener to Participant
class using the addEventListener()
method of Participant
Class. ParticipantEventListener
class has two methods :
onStreamEnabled
- Whenever a participant enables mic/webcam in the meeting, This event will be triggered and returnStream
.onStreamDisabled
- Whenever a participant disables mic/webcam in the meeting, This event will be triggered and returnStream
.
public class MeetingActivity extends AppCompatActivity {
private VideoView localView;
private VideoView participantView;
private CardView localCard, participantCard;
private ImageView localParticipantImg;
@Override
protected void onCreate(Bundle savedInstanceState) {
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.localParticipant);
localParticipantImg = findViewById(R.id.localParticipant_img);
//...
// setup local participant view
setLocalListeners();
}
private void setLocalListeners() {
meeting.getLocalParticipant().addEventListener(new ParticipantEventListener() {
@Override
public void onStreamEnabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
VideoTrack track = (VideoTrack) stream.getTrack();
localView.setVisibility(View.VISIBLE);
localView.addTrack(track);
localView.setZOrderMediaOverlay(true);
localCard.bringToFront();
}
}
@Override
public void onStreamDisabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
localView.removeTrack();
localView.setVisibility(View.GONE);
}
}
});
}
}
(b) Setting up Remote participant view
private final ParticipantEventListener participantEventListener = new ParticipantEventListener() {
// trigger when participant enabled mic/webcam
@Override
public void onStreamEnabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
localView.setZOrderMediaOverlay(true);
localCard.bringToFront();
VideoTrack track = (VideoTrack) stream.getTrack();
participantView.setVisibility(View.VISIBLE);
participantView.addTrack(track);
}
}
// trigger when participant disabled mic/webcam
@Override
public void onStreamDisabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
participantView.removeTrack();
participantView.setVisibility(View.GONE);
}
}
};
(c) Handle meeting events & manage participant's view
Add MeetingEventListener
for listening events such as Meeting Join/Left and Participant Join/Left.
public class MeetingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//...
// handle meeting events
meeting.addEventListener(meetingEventListener);
}
private final MeetingEventListener meetingEventListener = new MeetingEventListener() {
@Override
public void onMeetingJoined() {
// change mic,webCam icon after meeting successfully joined
toggleMicIcon();
toggleWebcamIcon();
}
@Override
public void onMeetingLeft() {
if (!isDestroyed()) {
Intent intent = new Intent(MeetingActivity.this, JoinActivity.class);
startActivity(intent);
finish();
}
}
@Override
public void onParticipantJoined(Participant participant) {
// Display local participant as miniView when other participant joined
changeLocalParticipantView(true);
Toast.makeText(MeetingActivity.this, participant.getDisplayName() + " joined",
Toast.LENGTH_SHORT).show();
participant.addEventListener(participantEventListener);
}
@Override
public void onParticipantLeft(Participant participant) {
// Display local participant as largeView when other participant left
changeLocalParticipantView(false);
Toast.makeText(MeetingActivity.this, participant.getDisplayName() + " left",
Toast.LENGTH_SHORT).show();
}
};
}
changeLocalParticipantView(isMiniView: Boolean)
function first checks 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 void changeLocalParticipantView(boolean isMiniView) {
if(isMiniView)
{
// show localCard as miniView
localCard.setLayoutParams(new CardView.LayoutParams(300, 430, Gravity.RIGHT | Gravity.BOTTOM));
ViewGroup.MarginLayoutParams cardViewMarginParams = (ViewGroup.MarginLayoutParams) localCard.getLayoutParams();
cardViewMarginParams.setMargins(30, 0, 60, 40);
localCard.requestLayout();
// set height-width of localParticipant_img
localParticipantImg.setLayoutParams(new FrameLayout.LayoutParams(150, 150, Gravity.CENTER));
participantCard.setVisibility(View.VISIBLE);
}else{
// show localCard as largeView
localCard.setLayoutParams(new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
ViewGroup.MarginLayoutParams cardViewMarginParams = (ViewGroup.MarginLayoutParams) localCard.getLayoutParams();
cardViewMarginParams.setMargins(30, 5, 30, 30);
localCard.requestLayout();
// set height-width of localParticipant_img
localParticipantImg.setLayoutParams(new FrameLayout.LayoutParams(400, 400, Gravity.CENTER));
participantCard.setVisibility(View.GONE);
}
}
(d) 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:
protected void onDestroy() {
if(meeting !=null)
{
meeting.removeAllListeners();
meeting.getLocalParticipant().removeAllListeners();
meeting.leave();
meeting = null;
}
if (participantView != null) {
participantView.setVisibility(View.GONE);
participantView.releaseSurfaceViewRenderer();
}
if (localView != null) {
localView.setVisibility(View.GONE);
localView.releaseSurfaceViewRenderer();
}
super.onDestroy();
}
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>
App Demo
Tadaa!! Our app is ready. Easy, isn't it?
Install and run the app on two different devices and make sure that they are connected to the internet.
This app only supports 2 participants, it does not manage more than 2 participants. If you want to handle more than 2 participant then checkout our Group call example HERE.
Conclusion
- In this blog, we have learned what videoSDK is, how to obtain an access token from the VideoSDK Dashboard, and how to create a one-to-one video chat app with the 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 this GitHub Repository.
- If you face any problems or have questions, Please join our Discord Community.
Schedule a Demo with Our Live Video Expert!
Discover how VideoSDK can help you build a cutting-edge real-time video app.
More Android Resources
- Android Live Streaming app with Java
- Android One-To-One video calling app with Kotlin
- Android Interactive Live Streaming App with Kotlin
- Android Video Conferencing App with Kotlin example code
- Android Interactive Live Streaming App with Kotlin example code
- Android Interactive Live Streaming App with Java example code
- Android Video Conferencing App with Java example code