JavaScript Quickstart Guide

Getting started

Hello there! In this guide, we'll build a video conferencing application using the 100ms JavaScript SDK. This guide doesn't make any assumptions related to the framework or library choices. In case you plan to use React, do check our React quickstart as well.

TL;DR - You can find the link to the complete example over here.

Prerequisites

To get started you must be familiar with rudimentary JavaScript and have nodejs installed on your machine.

Installing the dependencies

npm install --save @100mslive/hms-video-store@latest

Initializing the SDK

Let us start with initializing the libraries. We need an instance of HMSStore and HMSActions to get started. Copy the code snippet below and paste it into your project.

script.js
import { HMSReactiveStore } from '@100mslive/hms-video-store'; const hms = new HMSReactiveStore(); const hmsStore = hms.getStore(); const hmsActions = hms.getHMSActions();

hmsStore will hold the complete state of the application such as details of all the participants. We can also visualize this state at any time using the devtools extension.

hmsActions will help us perform actions such as joining the room, mute our audio and send messages.

Concepts

  • Room: When we join a conference call, the participants are said to be in a video call room.
  • Peer: A participant in the video call. You are the local peer while others are remote peers.
  • Track: Media. There are two types of track a peer can have - audio and video.

Joining a room

To join a room (a video call), we need to call the join method on hmsActions and it requires us to pass a config object. The config object must be passed the following fields:

  • userName: The name of the user. This is the value that will be set on the peer object and be visible to everyone connected to the room.
  • authToken: A client-side token that is used to authenticate the user. You can read about how to generate this token here.

For our application, let us collect both of these fields from the user using a form.

index.html
<form id="join"> <h2>Join Room</h2> <div class="input-container"> <input id="name" type="text" name="username" placeholder="Your name" /> </div> <div class="input-container"> <input id="token" type="text" name="token" placeholder="Auth token" /> </div> <button type="button" class="btn-primary" id="join-btn">Join</button> </form>

Join form

Congratulations! you now have an audio-only conference ready to use. If you have a friend join from another device, you can have a nice friendly chat with them.

Leaving the room

Before we go ahead with adding video, let us add a way to leave the room as well. We can call the leave method on hmsActions to leave the room.

We'll set up the leave method to be called whenever the user closes the window or refreshes the tab.

script.js
function leaveRoom() { hmsActions.leave(); } window.onunload = leaveRoom;

Adding video tiles

Let us next add a way to show a tile for every participant in the room. We'll need a list of peers connected to the room.

Fetching information from state

At any point in time we can get a list of peers with:

import { selectPeers } from '@100mslive/hms-video-store'; const peers = hmsStore.getState(selectPeers);

Let's take a moment to discuss how hmsStore works. The store maintains the state of the video call which includes the list of peers, the connection state of the room, the tracks, track states etc. We can use "selectors" that return a slice of the state to get the data piece we're interested in.

Subscribing to the state

The hmsStore is also reactive, and we can subscribe to the state. What this means is that we can register a function which will get called whenever the selected state changes. This allows us to write declarative code.

We'll subscribe to the peers state and render the tiles whenever something related to the peers changes.

script.js
import { HMSReactiveStore, selectPeers } from '@100mslive/hms-video-store'; // ... const peersContainer = document.getElementById('peers-container'); function renderPeers(peers) { // 1. clear the peersContainer // 2. loop through the peers and render a tile for each peer } hmsStore.subscribe(renderPeers, selectPeers);

For each peer, we'll render a <video> element and a <div> element with their name. We'll also make a helper function to create these DOM elements and add it to the peersContainer

script.js
const peersContainer = document.getElementById('peers-container');
// helper function to create html elements
function h(tag, attrs = {}, ...children) {
const newElement = document.createElement(tag);
Object.keys(attrs).forEach((key) => {
newElement.setAttribute(key, attrs[key]);
});
children.forEach((child) => {
newElement.append(child);
});
return newElement;
}
function renderPeers(peers) { // 1. clear the peersContainer
peersContainer.innerHTML = "";
// 2. loop through the peers and render a tile for each peer
peers.forEach((peer) => {
const video = h("video", {
class: "peer-video",
autoplay: true,
muted: true,
playsinline: true,
});
hmsActions.attachVideo(peer.videoTrack, video);
const peerContainer = h(
"div",
{
class: "peer-container"
},
video,
h(
"div",
{
class: "peer-name"
},
peer.name
)
);
peersContainer.append(peerContainer); }); } hmsStore.subscribe(renderPeers, selectPeers);

Now after you click join you should be able to see yourself!

Web Conference

Since we are subscribed to the peers state, our tiles will be re-rendered any time a new peer joins or leaves the room. We have a fully functional video conferencing application now 🎉🚀

Changing UI based on connection state

Right now, our join form shows even after we have joined the room. We need a way to know the connection state of the room and hide the form after we've connected.

We can do this by subscribing to the store with the selectIsConnectedToRoom selector.

script.js
import { selectIsConnectedToRoom, } from "@100mslive/hms-video-store"; function onConnection(isConnected) { if (isConnected) { form.classList.add("hide"); conference.classList.remove("hide"); leaveBtn.classList.remove("hide"); } else { form.classList.remove("hide"); conference.classList.add("hide"); leaveBtn.classList.add("hide"); } } hmsStore.subscribe(onConnection, selectIsConnectedToRoom);

Muting/unmuting local tracks

Right now we are publishing both audio and video feed of the user whenever they join the room. We may want to allow the user to mute/unmute their own tracks - both audio and video.

Let's add 2 buttons on the bottom of the page and call the methods on hmsActions to mute/unmute the local tracks.

script.js
import { selectIsLocalAudioEnabled, selectIsLocalVideoEnabled, } from "@100mslive/hms-video-store"; const muteAud = document.getElementById("mute-aud"); const muteVid = document.getElementById("mute-vid"); muteAud.addEventListener("click", () => { const audioEnabled = !hmsStore.getState(selectIsLocalAudioEnabled); hmsActions.setLocalAudioEnabled(audioEnabled); muteAud.textContent = audioEnabled ? "Mute" : "Unmute"; }); muteVid.addEventListener("click", () => { const videoEnabled = !hmsStore.getState(selectIsLocalVideoEnabled); hmsActions.setLocalVideoEnabled(videoEnabled); muteVid.textContent = videoEnabled ? "Hide" : "Unhide"; });

We fetch the current state of the local audio and video and toggle them whenever the buttons are clicked.

If you try it out now, you may notice that turning off the video makes the tile go blank but turning it on again doesn't bring it back. This is due to a change in video track requiring a call to attach again. To fix it let's call our renderPeers function whenever we change the state of the local video.

script.js
muteVid.addEventListener("click", () => { const videoEnabled = hmsStore.getState(selectIsLocalVideoEnabled); hmsActions.setLocalVideoEnabled(!videoEnabled); muteVid.textContent = !videoEnabled ? "Hide" : "Unhide";
renderPeers(hmsStore.getState(selectPeers));
});

Mute/Unmute

Mirroring local video

Each peer object has an isLocal property that indicates whether the peer is local or remote. When looping over the peer list we can use this property to decide whether to mirror the video or not.

script.js
function renderPeers(peers) { peersContainer.innerHTML = ""; if (!peers) { peers = hmsStore.getState(selectPeers); } peers.forEach((peer) => { const video = h("video", {
class: "peer-video" + (peer.isLocal ? " local" : ""),
autoPlay: true, muted: true }); hmsActions.attachVideo(peer.videoTrack, video); const peerContainer = h( "div", { class: "peer-container" }, video, h( "div", { class: "peer-name" },
peer.name + (peer.isLocal ? " (You)" : "")
) ); peersContainer.append(peerContainer); }); }

That wraps it up for this guide. We hope you had fun. There are plenty of cool stuff which can be done with our SDK, be sure to check the features section for more information.

Here's the complete example.