Building the Open-Source Conferencing App for Android
Estimated reading time: 26 minutesIn this part, we will explore the Android Conferencing app.
Let’s get started.
Prerequisites
Before we dive into running a fully featured Conference app for Android, ensure that you go through the following
-
Must read the first part of this tutorial and Prerequisites mentioned there.
-
Gone through the Quick Start with Mesibo Conferencing API - Android and have a basic familiarity with mesibo conferencing APIs.
-
Android Studio Installed
-
An Android Device to run the app
Before we get into the code, we recommend that you build the app and try it out, to have a feel of how the app works. This is a basic conferencing app with all the essential features. You can easily refer to the source code and the documentation, to modify it to your needs.
Build Instructions
Building the code is as simple as:
- Launch Android Studio
- Open the project android/java/MesiboConference from the folder where you have downloaded the code using the menu
File -> Open
- Build using menu
Build -> Rebuild Project
- It may take a while to build the project for the first time.
- Once the build is over, run on the device using the menu
Run -> Run (app)
- That’s it, you should see the welcome screen and then the login screen.
Running the App
Let us first run the app and do a brief walkthrough of the various features in the app. Once you are familiar with the various conferencing operations, we will get into the code walkthrough.
-
The first step is to Log-in using your email. Enter your name and email address. You’ll quickly receive a verification code. Enter it and you are in!
-
Once you have logged in, you can join a conference. If you have the room-id and PIN of a certain room, you can join an existing room by entering them. You can also Create a Room to hold a conference and invite others. To do this, select the Create Room option. Provide a room name and click Create Room. A room will be created and you will now start publishing your video.
-
To Invite other participants to the room, share the room credentials. Every room will have a group-id and pin. You can copy the invite text- containing the room-id and pin and share it with the participants who you want to join the room!
-
Any participant can now join the room by entering the room-id and the PIN. Once, they enter the room they will start publishing their stream and everyone in the room can view them.
-
You can also see your room history by clicking on the My Rooms button. It will display a list of all rooms that you are part of. Click on a room to quickly enter it without entering the PIN.
-
You can also mute participants, mute your own audio or video, chat with each participant and group, send media and files in chat, share your screen, etc. For per participant controls tap or click on their video. Control buttons will be visible. For your self stream controls, use the buttons at the bottom of the screen.
Source Code Walkthrough
There are two major components in this app:
-
Android Conferencing APIs, these APIs are used by your app for initiating a group call, publishing streams, subscribing to streams, etc. You can learn more about using the conferencing and streaming API in Quick Start with Mesibo Conferencing API - Android.
-
Administrative APIs, These are not the mesibo APIs but they are private APIs for the demo. You need to host them on your server to perform various administrative tasks such as log-in, creating a room, entering a room, etc. Your app connects to your server using these APIs. In turn, your server invokes the mesibo Group & User Management APIs internally to perform the required operation. For example, when you want to create a room, your server will create a mesibo group. When you want to join a room, your server will add you as a member to the mesibo group. After your user logs in, your server will create a mesibo user and generate an access token. We will learn more about this in the section Setting up the Admin API
Refer to the image below which demonstrates how the admin APIs work through your server and uses the mesibo group/user management APIs.
We will now go through the Android conferencing app source to learn how various conferencing features are implemented.
Log-in
The first step in the app is to authenticate the user and generate a mesibo access token for that user. Note that, mesibo is independent of the authentication and does not provide any APIs for implementing authentication. You need to implement your login method and then proceed to generate an access token on successful authentication.
In this demo app, we will be using an email-based login as an example. We will send an OTP to the user’s email. If the user enters that OTP, then they will be able to enter the demo. We make use of an Admin API called login
on the server end, to achieve this. Refer to the section on Setting up the Admin API- Log-in to learn more.
Using the login
REST API is a two-step process.
-
Pass the
appid
,name
, andemail
as parameters and invoke the REST API. -
An OTP will be sent to the email by the server. The user needs to enter this OTP. Invoke the REST API, with the parameter
code
containing the OTP. The server will now validate the OTP and email combination. If successful, it will send a mesibo access token in response.
Refer to the source code here for an example on invoking the login
REST API.
public static boolean emailLogin(String name, String email, String verificationCode, ResponseHandler handler) {
Bundle b = new Bundle();
b.putString("op", "login");
b.putString("appid", mContext.getPackageName());
b.putString("email", email);
b.putString("name", name);
b.putString("code", verificationCode);
handler.sendRequest(b, null, null);
return true;
}
If login is successful, your server will generate an access token using mesibo User Management API and send it to you in the response. You need to use this access token later while initializing the mesibo real-time API. Refer to the source code here.
if (response.op.equals("login") && !TextUtils.isEmpty(response.token)) {
AppConfig.getConfig().token = response.token;
...
}
Creating a Room
To create a room, you need to create a mesibo group. Since the client app can’t directly create a mesibo group (as it requires the secret app token), it will request Admin API to create a group.
The client invokes the setgroup
REST API with the mesibo access token
(that you generated in the login step), room name
, room resolution
as parameters. When this Admin API is called on your server, it will create a group using mesibo Group Management API. You can learn more about this in the section Setting up the Admin API- Create a Room
Refer to the source code here for an example on invoking the setgroup
REST API.
public static boolean createRoom(String name, int mSelectedResolution, String mesiboToken, ResponseHandler handler) {
Bundle b = new Bundle();
b.putString("op", "setgroup");
b.putString("token", mesiboToken);
b.putString("name", name);
b.putInt("resolution", mSelectedResolution);
handler.sendRequest(b, null, null);
return true;
}
The admin API will also generate PINs for the room and will store them in a database so that it can authenticate users wanting to join the room. A user needs to enter a PIN to join a room with a certain room-id.
Every mesibo group will have a group-id
. The app will be receiving the group-id
, in the response(in the field gid
) after calling setgroup
. We will be using this group-id to join the group call.
Pin Management
The admin API will randomly generate two numbers for each room, which can be used as a pin
to enter a room.
- pin, To be shared with users who need to be active participants in the room. They will be able to make voice and video calls at the conference.
- spin, Subscriber-only pin. To be shared with users who can only silently participate in the conference. They will not be able to make a call, but will only be able to view others.
If a room is created successfully using setgroup
, you will receive the room pin
and spin
in the response. Refer to the source code here
...
if(response.op.equals("setgroup") && response.result.equalsIgnoreCase("OK")){
SampleAPI.Room room = getRoom(response);
AppConfig.getConfig().activeRoom = room;
joinConferenceRoom((int) response.gid, room);
}
...
private SampleAPI.Room getRoom(SampleAPI.Response response){
if(null == response)
return null;
SampleAPI.Room room = new SampleAPI.Room();
long gid = response.gid;
if(gid <=0)
return null;
room.gid = gid;
room.name = response.name;
room.resolution = response.resolution;
room.pin = response.pin;
room.spin =response.spin;
room.publish = response.publish;
room.audio = mAudio;
room.video = mVideo;
room.duration = response.duration;
return room;
}
You can share the room-id and room-pin(either pin
for active participants or spin
for subscribe-only participants) with other users who you want to join the conference. Refer to the source code here to see how you can invite participants.
Joining a room
To join a room, you need to use the mesibo real-time conferencing APIs. However, before the user can use real-time APIs, the user must be a member of the group. Hence, the user first needs to request admin APIs to join a room using the room-id and the PIN. If they match, the admin API will add the user as a member of the group using mesibo group management APIs.
Refer to source code here for an example on invoking the joingroup
REST API.
public static boolean enterRoom(String gid, String pin, String mesiboToken, ResponseHandler handler) {
Bundle b = new Bundle();
b.putString("op", "joingroup");
b.putString("token", mesiboToken);
b.putString("gid", gid);
b.putString("pin", pin);
handler.sendRequest(b, null, null);
return true;
}
If joingroup
is successful, you can join a group call. Refer to source code JoinRoomActivity.java.
// Entering an existing room
if(response.op.equals("joingroup") && response.result.equalsIgnoreCase("OK")){
SampleAPI.Room room = getRoom(response);
AppConfig.getConfig().activeRoom = room;
joinConferenceRoom((int) response.gid, room);
}
Once the user is added to the group, the next step is to use the real-Time APIs to join the Group Call
Using the Real-Time API to join the Group Call
Once, you successfully create a room or enter a room, we will display the group call screen.
The app launches GroupCallActivity to show the group call screen. This, in turn, loads GroupCallFragment and starts the group call.
Refer to the source code JoinRoomActivity.java
private void joinConferenceRoom(Integer gid, SampleAPI.Room room) {
MesiboCall.getInstance().init(MainApplication.getAppContext());
Intent intent = new Intent(MainApplication.getAppContext(), GroupCallActivity.class);
intent.putExtra("gid", room.gid);
intent.putExtra("duration", room.duration);
if(room == null)
return;
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApplication.getAppContext().startActivity(intent);
}
Starting the Group Call
Once the fragment is loaded, we create a group call object and join the call. The app then starts publishing your stream, if you have permission to publish.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
mGroupcall = MesiboCall.getInstance().groupCall((MesiboCallActivity) getActivity(), mGid);
...
return view;
}
@Override
public void onResume() {
super.onResume();
if(!isGroupCallStarted)
startGroupCall();
}
private void startGroupCall(){
...
mGroupcall.join(this);
isGroupCallStarted = true;
...
//Publish self stream
mLocalPublisher = mGroupcall.createPublisher(0);
mLocalPublisher.setVideoSource(MesiboCall.MESIBOCALL_VIDEOSOURCE_CAMERAFRONT, 0);
mLocalPublisher.call(mRoom.audio, mRoom.video, this);
...
}
Viewing Others
Your app needs to implement the GroupCallListener so that it can notify you when other participant joins and leaves the room by calling MesiboGroupcall_OnPublisher
. It also notifies you when a participant subscribes to your video or voice streams through MesiboGroupcall_OnSubscriber
.
In this app, GroupCallFragment.java implements GroupCallListener.
When someone joins the room and starts publishing, you will receive their Participant object through MesiboGroupCall_OnPublisher.
@Override
public void MesiboGroupcall_OnPublisher(MesiboCall.MesiboParticipant participant, boolean joined) {
...
if (joined) {
...
participant.call(mRoom.audio, mRoom.video , this);
}
...
}
Using this Participant object, you can subscribe to them and view them. Refer to the documentation on subscribing to streams to learn more.
While subscribing to a stream, you also need to implement the GroupCallInProgressListener and pass it to the call
method which informs you of various participant events so that you can easily update your App UI or take necessary action, such as,
-
When you make a call using the
call
method and you are connected, MesiboGroupcall_OnConnected will be called. -
Once you are connected, you will be notified when you receive the video stream through the listener MesiboGroupcall_OnVideo or the audio stream through MesiboGroupcall_OnAudio
-
When a publisher mutes audio or video, you will be notified through MesiboGroupcall_OnMute
-
When a publisher starts talking, MesiboGroupcall_OnTalking will be called (Talk Detection).
-
When a publisher leaves the conference, MesiboGroupcall_OnHangup will be called
Displaying Streams
You need to use MesiboVideoView
to display self or other participant’s video. You can use MesiboVideoView
in your layout to display videos as you like.
When you receive the video stream from a participant MesiboGroupcall_OnVideo will be called. You can then use, setVideoView to display them.
Sorting Streams (Optional)
You can display the videos of participants in a grid or whatever fashion you like. Mesibo also provides a utility function to sort videos in a grid using the aspect ratio. To use this, you need to call the sort function with a list of streams and implement MesiboParticipantSortListener which will be called with the video cordinates. Note, this is an optional utility. You can always use your own method of sorting participants and displaying videos.
First we determine the available screen width and height:
if(mWidth < 0 || mHeight < 0) {
DisplayMetrics metrics = getDisplayMetrics(activity);
if(metrics != null) {
if(mWidth < 0)
mWidth = metrics.widthPixels;
if(mHeight < 0)
mHeight = metrics.heightPixels;
}
}
Here, each video is displayed in a ParticipantViewHolder containing a MesiboVideoView. So, in a grid, we will have a list of views. We will sort these views, based on the aspect ratio every time the grid is updated (when participant video added or removed, when video aspect ratio changes, etc). Refer to the source code here.
public void setStreams(ArrayList<ParticipantViewHolder> views) {
...
mFrameLayout.removeAllViewsInLayout();
ArrayList<Object> sorted = (ArrayList<Object>) mGroupCall.sort(this, views, mWidth, mHeight, 0, 8, null);
...
}
The position for each video in the grid is set in ParticipantSort_onSetCoordinates
@Override
public void ParticipantSort_onSetCoordinates(Object o, int position, float x, float y, float width, float height) {
ParticipantViewHolder vh = (ParticipantViewHolder)o;
vh.setCoordinates(position, x, y, width, height);
}
Refer to the documentation Display Streams to learn more.
Displaying List of Participants (Optional)
All publishers and subscribers in the conference rooms are members of a group. So, essentially you need to display a list of users.
For this, you may simply use a UI utility component from Android UI Modules - MesiboUserListFragment
.
MesiboUserListFragment
displays a list of users in different modes. Here, we use the mode MODE_SELECTCONTACT
. Refer to Android UI Modules Documentation to learn more.
private void onListParticipants(View v) {
Bundle bundle = new Bundle();
bundle.putLong("groupid", mRoom.gid);
MesiboUI.Config opt = MesiboUI.getConfig();
opt.mToolbarColor = 0xff00868b;
opt.selectContactTitle = "Participants";
opt.createGroupTitle = null;
UIManager.launchParticipantList(getActivity(), 0, MesiboUserListFragment.MODE_SELECTCONTACT, 0, bundle);
}
Conferencing Operations
We will now look at some of the common operations in conferencing such as muting a stream, sharing screen, talk detection, playing sound, hanging up, etc and the APIs used to implement it in the App.
-
For examples of operations carried on a local participant object(local publisher), such as sharing screen, etc refer to the source code here
-
For example, operations carried out on a remote participant object, such as muting a remote publisher, hanging up a remote publisher, etc. refer to the source code here. In the app, when you click on the video of a publisher the control buttons for that publisher appear.
Handling Mute
MesiboGroupcall_OnMute is called when the publisher mutes audio or video. Refer to the source code here
public void MesiboGroupcall_OnMute(MesiboCall.MesiboParticipant participant,
boolean audioMuted, boolean videoMuted) {
if(remote){
// Remote participant has muted
}
// Check mute status
if(audioMuted){
// Audio Muted
}
if(videoMuted){
// Video Muted
}
}
You can toggle the audio using toggleAudioMute and toggle the video using toggleVideoMute.
To learn more about handling mute refer to the documentation Muting Audio or Video.
Talk Detection
MesiboGroupcall_OnTalking is called when the participant starts or stops talking.
public void MesiboGroupcall_OnTalking(MesiboCall.MesiboParticipant participant, boolean talking) {
if(talking){
// If talking is true, participant started talking
// if it is false, participant stopped talking
// Handle talking. For example, Show a talking icon
}
}
Refer to the documentation about Talk Detection to learn more.
Screen Sharing
To start sharing the screen, set the video source of the local publisher to MESIBOCALL_VIDEOSOURCE_SCREEN
.
Refer to the source code in GroupCallFragment.java for an example where we switch the video source since at a time we are either sharing the screen or publishing from the camera on the app.
private void onLocalSwitchSource(View view){
if(mLocalPublisher == null)
return;
mLocalPublisher.switchSource();
int source = mLocalPublisher.getVideoSource();
int icon = -1;
if(MesiboCall.MESIBOCALL_VIDEOSOURCE_SCREEN == source){
icon = R.drawable.ic_baseline_camera_alt_24;
}
else {
icon = R.drawable.ic_mesibo_screen_sharing;
}
ImageButton switchSourcebutton = (ImageButton)view;
switchSourcebutton.setImageResource(icon);
}
If you wish you can create multiple publishers and set different video sources for each publisher. You will then be able to simultaneously share the screen and camera. Refer to the documentation on Set the Video Source to learn more.
Play Sound
You can use the utility function playInCallSound to play sound in the background in a group call. For example, in this app, we are playing a sound whenever a new participant joins the room. (When MesiboGroupcall_OnPublisher is called).
@Override
public void MesiboGroupcall_OnPublisher(MesiboCall.MesiboParticipant participant, boolean joined) {
...
if (joined) {
mGroupcall.playInCallSound(getContext(), R.raw.join, false);
}
...
}
Group Chat and One-to-One chat
For implementing chat, you can use the Mesibo Messaging UI Helper.
For group chat, simply set the group profile and use launchMessageView
to launch the chat UIfor the group.
protected void setRoom(SampleAPI.Room room){
if(room == null)
return;
mRoom = room;
mGroupProfile = new Mesibo.UserProfile();
mGroupProfile.address = null;
mGroupProfile.groupid = mRoom.gid;
mGroupProfile.name = mRoom.name;
Mesibo.setUserProfile(mGroupProfile, false);
}
...
public void onLaunchGroupMessagingUi(View view) {
MesiboUI.Config opt = MesiboUI.getConfig();
opt.mToolbarColor = 0xff00868b;
MesiboUI.launchMessageView(getActivity(), null, mGroupProfile.groupid);
}
Similarly, for one-to-one chat, create a user profile and call launchMessageView
private void setUserProfile(MesiboCall.MesiboParticipant participant) {
Mesibo.UserProfile user = new Mesibo.UserProfile();
user.address = participant.getAddress();
user.name = participant.getName();
Mesibo.setUserProfile(user, false);
}
...
public void onLaunchMessagingUi(View view) {
MesiboCall.MesiboParticipant p = getParticipant();
MesiboUI.Config opt = MesiboUI.getConfig();
opt.mToolbarColor = 0xff00868b;
MesiboUI.launchMessageView(view.getContext(), p.getAddress(), 0);
}
Refer to the documentation Launching Messaging UI in Android to learn more.
Hanging Up
Whenever a publisher hangs up, MesiboGroupcall_OnHangup will be called.
To, stop viewing a participant you need to call hangup on their participant object.
participant.hangup();
Refer to the documentation on Handling Hang Up to learn more.
Leaving the Room
To leave the room, call the leave
method on the group call object.
mGroupcall.leave()
In this app, we call leave when the local hangup button is pressed and when back button is pressed
Conclusion
In the next part, we will explore the iOS app.
open, source, zoom, android, conferencing