Building a group video chat web-app

Hermes
Agora.io
Published in
7 min readFeb 11, 2019

Update: April 25, 2024
This guide is outdated, please use the updated version built with the latest version of Agora’s web SDK.

Hey everyone, today I want to walk through how to build a simple group video chat web app, very similar to Google Hangouts, Skype or whichever other video chat platform you prefer. Given today’s fragmented JS landscape, I wanted to write this tutorial using the most basic versions of HTML, CSS and JS. Before you say it, I know I know, JQuery isn’t vanilla JS but Vanilla JS can be a bit verbose for certain DOM tasks, I chose to use JQuery to simplify a few things. We are going to cut a few corners and use Bootstrap so we don’t have to worry about writing too much custom CSS.

For the TLDR crowd: Check out the demo of the code in action on GitHub Pages.

Updated: June 4, 2020
This post and project has been updated to use the latest version of Agora.io’s Web SDK (v3.1.1)

Prerequisites

Core Structure (HTML)

Let’s start by laying out our basic html structure. There are a few UI elements we must have, such as the local video stream, the remote video streams, a toolbar that will contain buttons for toggling audio/video streams, a button to share our screen with the group, and lastly a way to leave the chat (we’ll add the buttons a little later).

Adding in CSS and JS

Now that we have our base we can start expanding. Using Bootstrap for our CSS we can quickly style our html with a few simple classes. In the above code, let's add the CSS links _(shown below)_ into the code where we see the comment block <!-- CSS includes go here -->.

While Boostrap is great but it isn’t a holistic solution, so I threw in a few extras CSS blocks within a custom CSS file (we’ll get to this a little later). This will help adjust a few elements that we won’t get perfect out of the box with Bootstrap. I also added the Font Awesome CSS framework because we are going to need to incorporate icons for the various buttons and FA makes it really simple.

As I mentioned, Bootstrap is great, but sometimes you still need a little bit of custom CSS. Here are the styling blocks for the above referenced style.css.

Adding UI elements

Now let’s add some buttons to control toggling the mic, video or leaving the channel and finish off the last remaining bits of our UI. This is where font awesome and bootstrap really make things simple. We will use a <button /> element and some FontAwesome icons.

The sections below fits in with the code above by replacing the comments
<!-- insert button to share screen --> and
<!-- insert buttons to toggle audio/video and leave/end call -->

We need to add some JS to control the buttons. JQuery will really help us here by simplifying the code for the various DOM operations which will allow the UI to feel dynamic for the user.

As you can see there is some added logic for keyboard controls. During testing I found having keyboard shortcuts made things move quicker. In the snippet above we have support for m, v, s, q to toggle mic, video, and screen-share and to leave the call (respectively).

I saved the above code into a file ui.js to keep it separate from the core video chat logic that we will write. Also let’s make sure to include the ui.js file within our html file (using the snippet below).

<script src="ui.js"></script>

Core Structure (JS)

Now that we the HTML/DOM structure laid out we can add in the JS. I chose to use Agora.io to simplify the heavy task of the WebRTC interface. I wrote a short post on how to get setup with Agora.io for anyone new to the Agora.io platform. In the code below we start by declaring and initializing the Client object. Once we have the Client object we can join/leave the channel but also we will add listeners for the various engine events.

Below I included some of the initial object declarations for the screen sharing. I will expand upon that implementation later on, as we add in the rest of the logic.

Note: This guide does not implement token authentication which is recommended for all RTE apps running in production environments.

For more information about token based authentication within the Agora platform please refer to this guide: https://bit.ly/3sNiFRs

One thing to note, all the Agora.io SDK event listeners should be at the top level, please don’t make the mistake of nesting them into the channel join callback. I made this mistake and it caused me to only have access to streams that joined the channel after me.

As you can see within the code above we have the ‘stream-added’ callback, this is where we will add logic to handle setting the first remote stream to the full screen video and every subsequent stream into a new div container within the remote-streams div which will give us the group functionality beyond just 1 to 1 video. Below is the function we would call every time a new remote stream is added and we want to have it add itself dynamically to the DOM.

One last note for this section, we have buttons that toggle the mic and video streams but we need to provide feedback to the remote users subscribed to the muted streams. Don’t worry Agora’s SDK provides some callbacks specially for these situations. Above you can see these cases are handled by the events such as mute-audio or mute-video (as well as their inverses for enabling the respective streams).

Enhancing the UI by handling remote stream actions

First let’s start by adding some extra divs with icons for a muted mic and a user icon when the video feed is disabled. I will use the local container as a reference as the remote stream containers will have similar structure.

The new divs will hold some Font Awesome icons that we can hide/show whenever the event callbacks are executed for on the local and corresponding remote streams. Now that we have some names for our elements we can easily control them within our event listeners.

the above snippet is part of the agora-interface.js

More frills

There’s a few effects that we can add to really enhance the user experience. First let’s consider what happens when the user wants a different stream to be the full screen. We’ll add a double click listener to each remote stream so when the user double clicks a remote stream it swaps the mini view with the full screen view.

the above snippet fits into addRemoteStreamMiniView() just before the closing bracket

Lastly let’s make sure that there is always a full screen stream as long as at least one stream is connected. We can use some similar methods as we did above.

I added some randomization so when the the full screen remote stream leaves the channel, one of the other remote streams is randomly selected and set to play in the full screen div.

Putting it all together

Now that we have all these snippets lets put them together and fill in the rest of the logic for how the web app should react to each event.

Please note: video sharing support has been added to Safari, but you must make sure the stream creation happens in an on-click event.

Let’s drop our JS includes into our html page to make the final connections. The below snippet fits into the main html (above) by replacing the comment <!-- JS Includes go here --> with the snippet below.

Testing Setup (webserver/https)

Since the camera permissions requires a secure (https) connection, before we can test our video chat app we must spin up a simple web server with a https connection. Browsers have Whitelisted the localhost, so we can use that to test.

If you want to test this out with friends you can run it locally in conjunction with ngrok, is a freemium service that creates this tunnel out from your local machine and provides an https url for use. In my experience this is one of the simplest ways to run an https secured web server on your local machine.

Once the server is ready we can run our test.

NOTE: for testing we will be using two (or more) browser tabs to simulate a local host and a single/multiple remote host(s).

Fin.

And just like that we are done! In-case you weren’t coding along or want to see the finished product all together, I have uploaded all the code to GitHub.

If you would like to see the demo in action, check out the demo of the code in action on GitHub Pages:

Please note: Due to high demand, I have updated the build so you will need to register for a free Agora.io account to get AppId to test the demo. If you need help, I have a quick 3 step guide

In thie code above, the App ID, channel name, token, and UID values are hard-coded in the agora-interface.js file. But in the base project I have since updated the code to include an input form to enter the App ID, token, uid and channel name.

Note: This project is meant for reference purposes and development environments, it is not intended for production environments.

Token authentication is recommended for all RTE apps running in production environments. For more information about token based authentication within the Agora platform please refer to this guide: https://bit.ly/3sNiFRs

If you enjoyed this post, I would recommend my How to Build a Live Broadcasting Web App where we’ll build a YouTube Live clone with a few extra features.

Thanks for taking the time to read my tutorial and if you have any questions, I invite you to join the Agora Developer Slack community. If you see any room for improvement feel free to fork the repo and make a pull request!

--

--

Hermes
Agora.io

Director of DevRel @ Agora.io … former CTO @ webXR.tools & AR Engineer @ Blippar — If you can close your eyes & picture it, I can find a way to build it