Building the Open-Source Conferencing App for iOS
Estimated reading time: 22 minutesIn this part, we will explore the iOS Conferencing app.
Let’s get started.
Prerequisites
Before we dive into running a fully featured Conference app for iOS, 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 - iOS and have a basic familiarity with mesibo conferencing APIs..
-
XCode Installed
-
An iPhone 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 Xcode
- Open the project ios/MesiboConference from the folder where you have downloaded the code using the menu
File -> Open
- Build using menu
Product -> Build
- 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
Product -> Run
- That’s it, you should see the welcome screen like below and then the login screen.
If you receive linker errors
If you receive linker errors, it means that your download was incomplete. One of the likely reasons is that you forgot to issue git lfs install
. There are two ways to fix it:
- Delete the entire repository and download again (do not forget
git lfs install
, as instructed above). Note that enablinggit lfs install
after partial download does not seem to work as expected. - OR, run
fetch_broken_download.sh
script
./fetch_broken_download.sh
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:
-
iOS 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 - iOS.
-
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 iOS 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.
-(void) login:(NSString *)name email:(NSString *)email code:(NSString *)code handler:(SampleAPI_onResponse) handler {
NSMutableDictionary *post = [[NSMutableDictionary alloc] init];
[post setValue:@"login" forKey:@"op"];
[post setValue:name forKey:@"name"];
[post setValue:email forKey:@"email"];
if(nil != code) {
[post setValue:code forKey:@"code"];
}
NSString *packageName = [[NSBundle mainBundle] bundleIdentifier];
[post setValue:packageName forKey:@"appid"];
[self invokeApi:post filePath:nil handler:handler];
}
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 example source code here.
if([op isEqualToString:@"login"]) {
mToken = (NSString *)[returnedDict objectForKeyOrNil:@"token"];
if(![SampleAPI isEmpty:mToken]) {
[self save];
[MesiboInstance reset];
}
}
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.
-(void) createRoom:(NSString *)name resolutoon:(int)resolution handler:(SampleAPI_onResponse) handler {
NSMutableDictionary *post = [[NSMutableDictionary alloc] init];
[post setValue:@"setgroup" forKey:@"op"];
[post setValue:[self getToken] forKey:@"token"];
[post setValue:name forKey:@"name"];
NSString *r = [NSString stringWithFormat:@"%d", resolution];
[post setValue:r forKey:@"resolution"];
[self invokeApi:post filePath:nil handler:handler];
}
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
- (IBAction)onCreateRoom:(id)sender {
if(_mRoom.text.length < 3) {
[self showError:@"missing or too short room Name"];
return;;
}
Resolution *r = [mResolutions objectAtIndex:mSelectedResolution];
[SampleAPIInstance createRoom:_mRoom.text resolutoon:r.resolution handler:^(int result, NSDictionary *response) {
if(SAMPLEAPP_RESULT_OK != result) {
[self showError:@"Create Failed"];
return;
}
NSInteger gid = [[response objectForKey:@"gid"] longValue];
[self dismissViewControllerAnimated:NO completion:^{
[mParent groupCallUi:gid video:YES publish:YES];
}];
}];
}
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.
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.
-(void) joinRoom:(NSString *)gid pin:(NSString *)pin handler:(SampleAPI_onResponse) handler {
NSMutableDictionary *post = [[NSMutableDictionary alloc] init];
[post setValue:@"joingroup" forKey:@"op"];
[post setValue:[self getToken] forKey:@"token"];
[post setValue:gid forKey:@"gid"];
[post setValue:pin forKey:@"pin"];
[self invokeApi:post filePath:nil handler:handler];
}
f joingroup
is successful, you can join a group call. Refer to source code JoinRoomViewController.m
-(void) joinRoom:(NSString *)gid pin:(NSString *)pin {
[SampleAPIInstance joinRoom:gid pin:pin handler:^(int result, NSDictionary *response) {
if(SAMPLEAPP_RESULT_OK != result) {
[self showError:@"Joining Room Failed"];
return;
}
[self groupCallUi:gid video:YES publish:YES];
}];
}
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 MesiboGroupCallController to show the group call screen. This, in turn, loads GroupCallView and starts the group call.
Refer to JoinRoomViewController.m
-(BOOL) groupCallUi:(uint32_t)gid video:(BOOL)video publish:(BOOL)publish {
MesiboGroupCallController *vc = [[MesiboGroupCallController alloc] initWithGid:gid];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
UIViewController *me = self;
[MesiboInstance runInThread:YES handler:^{
[me presentViewController:vc animated:YES completion:nil];
}];
return YES;
}
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.
See GroupCallView.m
- (void)startCall {
/* create a group call instance and join the room */
mGc = [MesiboCallInstance groupCall:self groupid:mGid];
[mGc join:self];
/* publish streams */
MesiboParticipant *p = [mGc createPublisher:0];
[p setVideoSource:MESIBOCALL_VIDEOSOURCE_CAMERAFRONT index:0];
[mPublishers addObject:p];
[p call:YES video:YES listener:self];
}
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, GroupCallView.m implements GroupCallListener.
When someone joins the room and starts publishing, you will receive their Participant object through MesiboGroupCall_OnPublisher.
- (void)MesiboGroupcall_OnPublisher:(MesiboParticipant * _Nonnull)p joined:(BOOL)joined {
/* we got a new publisher, subscribe to them*/
if (joined) {
int pos = [self getParticipantPosition:mPublishers p:p];
if(pos >= 0) {
[mPublishers removeObjectAtIndex:pos];
}
[mPublishers addObject:p];
[p call:YES video:(YES) listener:self];;
} else {
[self removeParticipant:p];
[self setStreams];
}
}
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 coordinates. Note, this is an optional utility. You can always use your own method of sorting participants and displaying videos.
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.
-(void) setStreams {
...
NSArray *sorted = [mGc sortStreams:self views:mStreams
width:mWidth height:mHeight start:0 size:mStreams.count params:nil];
...
}
The position for each video in the grid is set in ParticipantSort_onSetCoordinates
- (void)ParticipantSort_onSetCoordinates:(id _Nonnull)o
position:(int)position x:(float)x y:(float)y width:(float)width height:(float)height {
ParticipantViewHolder *pv = (ParticipantViewHolder *)o;
[pv setCoordinates:position x:x y:y width:width height:height];
}
Refer to the documentation Display Streams to learn more.
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.
Handling Mute
MesiboGroupcall_OnMute is called when the publisher mutes audio or video.
-(void) MesiboGroupcall_OnMute:(MesiboParticipant *)participant
audio:(BOOL)audioMuted video:(BOOL)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.
-(void) MesiboGroupcall_OnTalking:(MesiboParticipant *)participant talking:(BOOL)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
.
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.
NSURL *sound = [NSURL fileURLWithPath:@"file:///path/to/audiofile/"];
[GroupCallInstance playInCallSound:sound]
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 UI for the group.
Similarly, for one-to-one chat, create a user profile and call launchMessageView
.
For example,
- (IBAction)onLaunchMessagingUIModule:(id)sender {
//requires pod mesibo-ui
[MesiboUI launchMessageViewController:self profile:mProfile];
}
Refer to the documentation Launching Messaging UI in iOS learn more.
Hanging Up
Whenever a publisher hangs up, MesiboGroupcall_OnHangup
will be called.
To, stop viewing a participant you need to call hang up 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.
-(void) onHangup:(id)sender {
[mGc leave];
[mController dismiss];
}
In this app, we call leave when the local hangup button is pressed.
Conclusion
In the next part, we will explore the Javascript(Web) app.
open, source, zoom, ios, objective-c, conferencing