How To Build A Drop-in Video Chat Application Using Android
Tags: android, agoraio, videocall, java
Published: 2020-05-14 01:35:39

Many cities and states have been under lockdown since the outbreak of the coronavirus epidemic. During this difficult time, we’re all looking for new ways to stay connected and support each other. This is when social networking applications such as [Houseparty](https://play.google.com/store/apps/details?id=com.herzick.houseparty) become especially relevant and helpful.

These applications let users meet up and have fun with their friends without having to leave their homes. Users can enter their friend’s virtual room by just clicking a button. Houseparty, in particular, also provides some built-in games that users can play together.

If you’ve ever wondered how these cool applications are made, read on! This blog post will help get you started on the basics of building a similar social networking application on Android.

#Prerequisites
1. A basic-to-intermediate understanding of Java and Android SDK
2. [Agora.io developer account](https://www.agora.io/en/blog/how-to-get-started-with-agora)
3. Android Studio and 2 Android devices

_Please Note: While no Java/Android knowledge is needed to follow along, certain basic concepts in Java/Android won’t be explained along the way._

#Overview
This guide will go over the steps for building a social networking application similar to Houseparty. This is a list of the core features that will be included in our app:

* Users can create and login into their account. User account information will be saved in Google Firebase Realtime Database.
* Users can set up virtual rooms to host video calls.
* Users can configure the accessibility of their virtual rooms. “Public” rooms are open for all friends to join and “private” rooms are invitation-only.
* During a video call, users can send private messages to another user in the same room by double-clicking on that user’s remote video.
* Users can chat with friends who are not in the room by clicking a button next to their names in the friend list.

_You can find my Github [demo app](https://github.com/ysc1995/HousepartyAgora) as a reference for this article._

#Set Up New Project
To start, let’s open Android Studio and create a new, blank project.
1. Open Android Studio and click __Start a new Android Studio project__.
2. On the __Choose your project__ panel, choose __Phone and Tablet __> __Empty Activity__, and click __Next__.
3. Click __Finish__. Follow the on-screen instructions if you need to install any plug-ins.

###Add Project Permissions
Add project permissions in the __/app/src/main/AndroidManifest.xml__ file for device access according to your needs:
```
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.housepartyagora">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
<!-- The Agora SDK requires Bluetooth permissions in case users are using Bluetooth devices. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
```

###Integrate the SDK
Add the following line in the __/app/build.gradle__ file of your project:
```
dependencies {
    ...
    implementation 'com.google.firebase:firebase-database:16.0.4'
    //Agora RTC SDK for video call
    implementation 'io.agora.rtc:full-sdk:3.0.0.2'
    //Agora RTM SDK for chat messaging
    implementation 'io.agora.rtm:rtm-sdk:1.2.2'
}
```

#Setup Google Firebase Database
Since our application allows users to search and add their friends to their friend lists in the app, we need to use [Firebase Realtime Database](https://firebase.google.com/products/realtime-database) to save users’ account information. Here are the steps you need to connect your application to Firebase Realtime Database:
1. In your Android Studio, Click “__Tools__”, then select “__Firebase__”.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vg11lc4u9arrnu1f7kka.png)

2. On the right hand side, you should see a Firebase assistant tab showing up. Find “__Realtime Database__” and click “__Save and retrieve Data__”.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ki616wads6ndsobggbfx.png)
3. Then you should see the detailed page for Realtime Database. Click the “__Connect to Firebase__” button and “__Add the Realtime Database to your app__” button. Follow the on-screen instruction, if any.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cducp6joc3lfm7b6yh0n.png)
4. Now your application is connected to Firebase Realtime Database. The last thing you need to do is to go to your Firebase console and change the database rules. Remember to select the Realtime Database instead of the Cloud Firestore. Change the rules for read and write to “__true__” so that you can have access to the database.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q2t0qnd5d3a2fqf270hh.png)

#User Login
First, let’s create a landing page for our application.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tavivgll523qhdxgjsqz.png)
_Please Note: You can find the .xml file [here](https://github.com/ysc1995/HousepartyAgora/blob/master/app/src/main/res/layout/activity_splash.xml)._

If the user clicks “__SIGN UP__” button, we will jump to sign up page. If the user clicks “__I Already Have An Account__” text, we will jump to the login page. Let’s implement the activities transaction logic using Intent.
```java
public void onLoginButtonClick(View view) {
    Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
    startActivity(intent);
}

public void onSignUpButtonClick(View view) {
    Intent intent = new Intent(SplashActivity.this, SigninActivity.class);
    startActivity(intent);
}
```
Now, let’s create the UIs for the login page and sign up page.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tnlnhz2pnrbdn6b2rluq.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/a2l45jksz3s0azp1jlrs.png)
_Please Note: You can find the .xml file for Login page [here](https://github.com/ysc1995/HousepartyAgora/blob/master/app/src/main/res/layout/activity_login.xml) and Sign Up page [here](https://github.com/ysc1995/HousepartyAgora/blob/master/app/src/main/res/layout/activity_signin.xml)._

When the user clicks the “__Next__” button, we need to get the user’s name and pass that to the next activity, __VideoCallActivity__, to start the video call. Here is the code for that in the Login activity, and the Signup activity will be similar.
```java
public void onLoginNextClick(View view) {
    EditText userNameEditText = findViewById(R.id.et_login_user_name);
    String userName = userNameEditText.getText().toString();

    if(userName == null || userName == "") {
        Toast.makeText(this, "user name cannot be empty", Toast.LENGTH_SHORT).show();
    }else {
        Intent intent = new Intent(this, VideoCallActivity.class);
        intent.putExtra("userName", userName);
        startActivity(intent);
    }
}
```

#Save User Account In Firebase Database
In the __onCreate__ method in the __VideoCallActivity__, we need to save user’s information in the Firebase Database. First, get the database reference by calling:

```java
mRef = FirebaseDatabase.getInstance().getReference("Users");
```

Then we call __setValue__ to save user information as a child in the database. User information is kept in the DBUser format. In a DBUser object, it maintains a user name, a uid, a user room state and a list of friends.
```java
mRef.push();
mRef.child(userName).setValue(new DBUser(userName, user.getAgoraUid(), localState, DBFriend));
```

At this point, if you run this application, you should be able to see new user information saved in your database after you login into the app.

#Start Video Call
After the user logged in into the app, he is in his virtual room by default. This user should be in a video call channel so that his friend can join his channel for a call. So in the __VideoCallActivity__, we need to implement the video call logic. But how to start a video call? It seems very complicated to do that. Luckily, I found out that [__Agora Video SDK__](https://docs.agora.io/en/Video/product_video?platform=All%20Platforms) provides the easiest way to start a video call.

First, let’s create a UI for this activity:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cwrq288htyjhibf8cust.png)
_Please Note: You can find the .xml file [here](https://github.com/ysc1995/HousepartyAgora/blob/master/app/src/main/res/layout/activity_video_call.xml)._

Then, in the __onCreate()__ method in the __VideoCallActivity__, let’s do following several things:
1. Initialize Agora RtcEngine
2. Setup local video Canvas
3. Join channel

###1. Initialize Agora Rtc Engine
In order to initialize the Agora video engine, just simply call __RtcEngine.create(context, appID, RtcEventHandler)__ to create a RtcEngine instance.
```java
mRtcEngine = RtcEngine.create(getBaseContext(), appID, mRtcEventHandler);
```

In order to get the [App ID](https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#a-nameappidaapp-id) in the parameter, follow these steps:
1. [Create an Agora project](https://docs.agora.io/en/Agora%20Platform/manage_projects?platform=All%20Platforms) in the Agora Console.
2. Click the [Project Management](https://sso.agora.io/login/?response_type=code&client_id=59T2cPE9by201sbXpExrCEVNgIi0su1h&redirect_uri=https%3A%2F%2Fconsole.agora.io%2Fapi%2Fv2%2Foauth) tab on the left navigation panel.
3. Click “Create” and follow the on-screen instructions to set the project name, choose an authentication mechanism, and click “Submit”.
4. On the Project Management page, find the App ID of your project.

The __mRtcEventHandler__ is a handler to manage different events occurring with the RtcEngine. Let’s implement it with some basic event handlers needed for this application.
```java
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
    @Override
    // Listen for the onJoinChannelSuccess callback.
    // This callback occurs when the local user successfully joins the channel.
    public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                user.setAgoraUid(uid);
                mRef.child(getUserName()).setValue(new DBUser(getUserName(), user.getAgoraUid(), localState, DBFriend));
            }
        });
    }

    @Override
    // Listen for the onFirstRemoteVideoDecoded callback.
    // This callback occurs when the first video frame of a remote user is received and decoded after the remote user successfully joins the channel.
    // You can call the setupRemoteVideo method in this callback to set up the remote video view.
    public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                SurfaceView mRemoteView = RtcEngine.CreateRendererView(getApplicationContext());

                mRemoteView.setZOrderOnTop(true);
                mRemoteView.setZOrderMediaOverlay(true);
                mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
            }
        });
    }

    @Override
    // Listen for the onUserOffline callback.
    // This callback occurs when the remote user leaves the channel or drops offline.
    public void onUserOffline(final int uid, int reason) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                onRemoteUserLeft(uid);
            }
        });
    }
};
```
Please check the comments on the top of each event handler methods to have a better understanding of them. For more RtcEngine event handlers that you can use, check the [__Agora Rtc API document__](https://docs.agora.io/en/Video/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler.html).

_Please Note: Some of the logic to show video views on the screen is hidden. You can check the [Github demo app](https://github.com/ysc1995/HousepartyAgora/blob/master/app/src/main/java/com/example/housepartyagora/acitivities/VideoCallActivity.java) for a better understanding of how to display and remove video views on the screen dynamically._

###2. Setup local video Canvas
To start a local video (see yourself on the screen), you need to call two functions: __enableVideo()__ and __setupLocalVideo()__ on a RtcEngine instance. In function __setupLocalVideo()__, a surfaceView created by calling __RtcEngine.CreateRenderView(context)__ is passed as a parameter.
```java
mRtcEngine.enableVideo();
mRtcEngine.enableInEarMonitoring(true);
mRtcEngine.setInEarMonitoringVolume(80);

SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
surfaceView.setZOrderOnTop(false);
surfaceView.setZOrderMediaOverlay(false);
```

###3. Join channel
Now we are ready to join the channel by calling __joinChannel()__ on the RtcEngine instance. The __channelName__ is the user name we get from the previous activity. In this case, each user will join into a video call channel with his entered user name when he login.
```java
mRtcEngine.joinChannel(token, channelName, "Extra Optional Data", 0);
```
_Please Note: The token in the parameter can be set to null. You can get more information about token [here](https://docs.agora.io/en/faqs/token_usage_generation_description#function-of-a-token)._

By calling this function and successfully joining the channel, the RtcEngineEventHandler will trigger the __onJoinChannelSuccess()__ method that we implemented in the previous step. It will return a unique id from Agora server. We need to update the user information with the uid in the database.
```java
@Override
public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            user.setAgoraUid(uid);
            mRef.child(getUserName()).setValue(new DBUser(getUserName(), user.getAgoraUid(), localState, DBFriend));
        }
    });
}
```

###4. Search and add friends
Like a real social application, a user should be able to search his friends by names and add them in his friend list. So when user clicks on the top right button, the app should show a search friend panel like this:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/03upiei5xhxfgyx9kcfs.png)
The user can enter his friend’s name in the edit text and click the search button. We need to search his friend’s name in the database and display the result in the recycler view. Here is how to search people by name in the database:
```java
childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
        DBUser result = dataSnapshot.getValue(DBUser.class);

        searchFriendList.add(result);
        mRef.orderByChild("name").startAt(searchFriendName).endAt(searchFriendName + "\uf8ff").removeEventListener(childEventListener);

        mFriendListRecyclerViewAdapter = new FriendListRecyclerViewAdapter(searchFriendList);
        mFriendListRecyclerViewAdapter.setOnItemClickListener(new FriendListRecyclerViewAdapter.ClickListener() {
            @Override
            public void onItemClick(int position, View v) {
                addFriend(searchFriendList.get(position).getName());
                mSearchFriendEditText.setText("");
                searchFriendList.clear();
                mFriendListRecyclerView.setAdapter(mFriendListRecyclerViewAdapter);
            }
        });
        RecyclerView.LayoutManager manager = new GridLayoutManager(getBaseContext(), 1);
        mFriendListRecyclerView.setLayoutManager(manager);

        mFriendListRecyclerView.setAdapter(mFriendListRecyclerViewAdapter);
    }

    ...
};

mRef.orderByChild("name").startAt(searchFriendName).endAt(searchFriendName + "\uf8ff").addChildEventListener(childEventListener);
```
In the recycler view, we will display the friend name searched in the database with a “__Add__” button on the side. If the user clicks the “__Add__” button, that friend is added in the user’s friend list. We also need to update the user’s friend list in the database.
```java
public void addFriend(String userName) {
    DBFriend.add(userName);
    mRef.child(this.userName).setValue(new DBUser(this.userName, user.getAgoraUid(), localState, DBFriend));
}
```

###5. Join a friend
Since we have an updated friend list, we can display the user’s friends panel when the user clicks on the top left button. Now the user can see his friend list and choose which friend to join the call. On the side of his friend’s name, create a “Join” button for the user to join this friend’s virtual room and have a video call with him.
```java
public void joinFriend(String friendName){
    channelName = friendName;
    finishCalling();
    startCalling();
}
```
Let’s change the __channelName__ to the user’s friend’s name so that when the __startCalling__ method is triggered, the user will join a different channel with the same name as the name of his friend.
```java
private void startCalling() {
    //set up local video canvas
    mRtcEngine.enableVideo();
    mRtcEngine.enableInEarMonitoring(true);
    mRtcEngine.setInEarMonitoringVolume(80);

    SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
    mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
    surfaceView.setZOrderOnTop(false);
    surfaceView.setZOrderMediaOverlay(false);
  
    //join the channel
    mRtcEngine.joinChannel(null, channelName, "Extra Optional Data", 0);}
```
If the user wants to leave the call from his friend’s room and go back to his own virtual room, he can click on the “X” button at the center bottom to achieve that. Let’s create a boolean called __isLocalCall__ to track if the user is in his own virtual room or not. We need to set the __channelName__ as the user’s __userName__ so that he will join the channel with the same channel name as his username after calling __startCalling__ method. In this way, he is back to his virtual room.
```java
if (isLocalCall) {
    //when the user is in his own room
    ...
    }
}else {
    //when user is joining other people's room
    //leave that room and come back to user's own room
    isLocalCall = true;
    finishCalling();
    channelName = userName;
    startCalling();
}
```

###6. Lock the room
Sometimes, a user wants to set his own virtual room to become a “private” room so that no one else can join his room except those who are already in the room. So how should we achieve that?

Create a String called __localState__ to track the state of the room. There are two states: “Open” or “Lock”. By default, a room state is “Open”. When the user clicks the “X” button at the center bottom while he is in his own virtual room (which mean isLocalCall == true), we need to set the room state to “Lock” to set the room state to “private”. If he clicks that again, we need to set the room state back to “Open” again. Also, we have to update the room state information in the database so that other users can know the current state for this room.
```java
if (isLocalCall) {
    //when the user is in his own room
    if (localState.equals(Constant.USER_STATE_LOCK)) {
        //set the room to public
        localState = Constant.USER_STATE_OPEN;
        mRef.child(this.userName).setValue(new DBUser(this.userName, user.getAgoraUid(), localState, DBFriend));
        showToast("Room set to public");
    }else {
        //set the room to private so that no one can join the room
        localState = Constant.USER_STATE_LOCK;
        mRef.child(this.userName).setValue(new DBUser(this.userName, user.getAgoraUid(), localState, DBFriend));
        showToast("Room set to private");
    }
}else {
    //when user is joining other people's room
    //leave that room and come back to user's own room
    isLocalCall = true;
    finishCalling();
    channelName = userName;
    startCalling();
}
```
After that, every time before a user joins a friend’s channel, we need to check if that friend’s room is not private. Otherwise, we will display a toast on the screen.
```java
joinFriendChildEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
        DBUser result = dataSnapshot.getValue(DBUser.class);
        if (result.getState().equals(Constant.USER_STATE_OPEN)) {
            joinFriend(DBFriend.get(position));
            mShowFriendLinearLayout.setVisibility(View.GONE);
        }else {
            showToast(DBFriend.get(position) + "'s room is locked. You can message him to say hi!");
        }

        mRef.orderByChild("name").startAt(DBFriend.get(position)).endAt(DBFriend.get(position) + "\uf8ff").removeEventListener(joinFriendChildEventListener);
    }

    ...
};
mRef.orderByChild("name").startAt(DBFriend.get(position)).endAt(DBFriend.get(position) + "\uf8ff").addChildEventListener(joinFriendChildEventListener);
```
At this point, users in our application are able to search and add friends, join a friend’s virtual room and lock his virtual room. Now let’s implement the chat messaging functionality for our application.

#Chat Messaging
Implementing chat messaging functionality is also very simple using [__Agora Messaging SDK__](https://docs.agora.io/en/Real-time-Messaging/product_rtm?platform=All%20Platforms).

###Start RTMClient
In order to enable chatting function in our application, we need to create a __RtmClient__ using Agora Messaging SDK.
```java
mRtmclient = RtmClient.createInstance(mContext, appID, new RtmClientListener() {
        @Override
        public void onConnectionStateChanged(int state, int reason){
            for (RtmClientListener listener : mListenerList) {
                listener.onConnectionStateChanged(state, reason);
            }
        }@Override
        public void onMessageReceived(RtmMessage rtmMessage, String peerId) { ... }
});
```
Here, we pass the same __appID__ as we used when we initialize the Agora Video engine.

In the __onConnectionStateChanged()__ callback, we are calling __RtmClientListener__. We will implement this later in the Message activity.

In the __onCreate__ method in the VideoCallActivity, we need to login __RtmClient__.
```java
mRtmClient.login(null, userName, new io.agora.rtm.ResultCallback<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        ...
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        ...
    }
});
```
We use the same __userName__ as the one we used for video call.

Now, let’s create a “Chat” button next to the “Join” button in user’s friend list so that when user clicks it, it will display a chat messaging panel like this:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sjzw2hqsc3eqm6oelngt.png)
User can edit his message in the edit text and send the message to his friend by clicking the “Send” button. The messages between the user and his friend will be displayed in the recycler view.

First implement the __onClick__ logic for the “Send” button.
```java
public void onClickSend(View v) {
    String content = mMsgEditText.getText().toString();
    RtmMessage message = mRtmClient.createMessage();
    message.setText(content);

    // step 2: send message to peer
    mRtmClient.sendMessageToPeer(mPeerId, message, mChatManager.getSendMessageOptions(), new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        ...
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        ...
    }
    });
}
```
Then we need to add logic to receive the chat messages. To receive private chat messages, we need to register __RtmClientListener__. Remember that when we created the RtmClient instance, we were calling RtmClientListener in the callbacks. Now, let’s implement this. In the callback __onMessageReceived()__, we put the logic to show the message on the RecyclerView.
```java
class MyRtmClientListener implements RtmClientListener {

    @Override
    public void onConnectionStateChanged(final int state, final int reason) {
        ...
    }

    @Override
    public void onMessageReceived(final RtmMessage message, final String peerId) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String content = message.getText();
                if (peerId.equals(mPeerId)) {
                    MessageBean messageBean = new MessageBean(peerId, content,false);
                    messageBean.setBackground(getMessageColor(peerId));
                    mMessageBeanList.add(messageBean);
                    mMessageAdapter.notifyItemRangeChanged(mMessageBeanList.size(), 1);
                    mRecyclerView.scrollToPosition(mMessageBeanList.size() - 1);
                } else {
                    MessageUtil.addMessageBean(peerId, content);
                }
            }
        });
    }
    ...
}
```
Now we are able to let users chat within the app. But they only can start chatting by clicking a button in their friend list. Let’s make it a little fancier! We want to allow the user to start chatting with his friend by double clicking on this friend’s remote video when they are in a video call. How can we achieve that.

First, we need to add the double click listener for the VideoViewContainer. Then, when the double click is triggered, we can get the remote user’s Agora uid and find that user’s name in the database.
```java
chatSearchChildEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
        DBUser result = dataSnapshot.getValue(DBUser.class);
        startMessaging(result.getName());

        mRef.orderByChild("uid").startAt(user.mUid).endAt(user.mUid + "\uf8ff").removeEventListener(chatSearchChildEventListener);

    }

    ...
};

mRef.orderByChild("uid").startAt(user.mUid).endAt(user.mUid + "\uf8ff").addChildEventListener(chatSearchChildEventListener);
```
After that, we can follow the previous steps to start the messaging functionality by passing the user name.

#Switch Camera And Audio Mute
At this point, all the core functionalities in our application are achieved. Let’s implement the switch camera and audio mute buttons onClick logic.

###Switch camera
This button is to switch from using your mobile’s front camera to rear camera or vise versa. To do that, simply call __switchCamera()__ on the RtcEngine instance.
```java
mRtcEngine.switchCamera();
```

###Audio mute/unmute
Sometimes users want to mute their input voice during a video call. That’s also easy to implement by just calling __muteLocalAudioStream()__ on the RtcEngine instance and passing whether the user is already muted in the parameter.
```java
mRtcEngine.muteLocalAudioStream(isMuted);
```

#Build And Test on Device
Now let’s run our application!

Go to Android Studio, make sure your Android device is plugged in, and click __Run__ to build the application on your device. Remember to build the application on two devices to start the video call.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/htzz0hlx2bjnapy4qrv7.gif)

#Done!
Congratulations! You just built yourself a social application similar to Houseparty!

Thank you for following along. If you want to see more features such as push notification, please leave a comment below! Here is the email address for any of the questions you might have: devrel@agora.io.