JavaScript Quickstart Guide
Overview
This guide will walk you through step-by-step instructions to create a video conferencing application using the 100ms JavaScript SDK and test it locally on your device. If you plan to use React, do check our React quickstart as well.
Please check our basic concepts guide to understand the concepts like rooms, templates, peers, etc.
TL;DR - Try out this complete example in CodeSandbox.
You can join the above room using room code from dashboard. Refer this for more details about room code.
Try this out locally
In this section, we will walk you through a complete code example that will enable you to create a local video-conferencing application in under 10 minutes and test audio/video functionality along with a couple of other essential functionalities like mute/unmute audio and video.
We will use ParcelJS, a web application bundler that requires zero configuration. If you wish to use any other library or framework, you can set up your app using that.
Initialize a project
You can initialize a project using npm init
or yarn init
. While initializing the project you can enter the details for your project as you wish.
Install ParcelJS & 100ms SDK
Then, install ParcelJS and 100ms SDK into your app like below
- using yarn:
yarn add --dev parcel yarn add @100mslive/hms-video-store
- using npm:
npm install --save-dev parcel npm install @100mslive/hms-video-store
Project setup
Now that the dependencies are installed, let's create basic source files for our video-conferencing application. Let's create the files and folders in the below manner:
100ms-test - index.html - src - index.js - styles.css
Complete code example
Next, copy the below code snippets and paste it into the respective files created in the above step.
import { HMSReactiveStore, selectIsLocalAudioEnabled, selectIsLocalVideoEnabled, selectPeers, selectIsConnectedToRoom, selectVideoTrackByID, } from "@100mslive/hms-video-store"; // Initialize HMS Store const hmsManager = new HMSReactiveStore(); hmsManager.triggerOnSubscribe(); const hmsStore = hmsManager.getStore(); const hmsActions = hmsManager.getActions(); // HTML elements const form = document.getElementById("join"); const joinBtn = document.getElementById("join-btn"); const conference = document.getElementById("conference"); const peersContainer = document.getElementById("peers-container"); const leaveBtn = document.getElementById("leave-btn"); const muteAudio = document.getElementById("mute-aud"); const muteVideo = document.getElementById("mute-vid"); const controls = document.getElementById("controls"); // store peer IDs already rendered to avoid re-render on mute/unmute const renderedPeerIDs = new Set(); // Joining the room joinBtn.onclick = async () => { const roomCode = document.getElementById("room-code").value const userName = document.getElementById("name").value const authToken = await hmsActions.getAuthTokenByRoomCode({ roomCode }) hmsActions.join({ userName, authToken }); }; // Leaving the room async function leaveRoom() { await hmsActions.leave(); peersContainer.innerHTML = ""; } // Cleanup if user refreshes the tab or navigates away window.onunload = window.onbeforeunload = leaveRoom; leaveBtn.onclick = leaveRoom; // Helper function to create html elements function createElementWithClass(tag, className) { const newElement = document.createElement(tag); newElement.className = className; return newElement; } // Render a single peer function renderPeer(peer) { const peerTileDiv = createElementWithClass("div", "peer-tile"); const videoElement = createElementWithClass("video", "peer-video"); const peerTileName = createElementWithClass("div", "peer-name"); videoElement.autoplay = true; videoElement.muted = true; videoElement.playsinline = true; peerTileName.textContent = peer.name; hmsStore.subscribe((track) => { if (!track) { return; } if (track.enabled) { hmsActions.attachVideo(track.id, videoElement); } else { hmsActions.detachVideo(track.id, videoElement); } }, selectVideoTrackByID(peer.videoTrack)); peerTileDiv.append(videoElement); peerTileDiv.append(peerTileName); renderedPeerIDs.add(peer.id); return peerTileDiv; } // display a tile for each peer in the peer list function renderPeers() { const peers = hmsStore.getState(selectPeers); peers.forEach((peer) => { if (!renderedPeerIDs.has(peer.id) && peer.videoTrack) { peersContainer.append(renderPeer(peer)); } }); } // Reactive state - renderPeers is called whenever there is a change in the peer-list hmsStore.subscribe(renderPeers, selectPeers); // Mute and unmute audio muteAudio.onclick = async () => { const audioEnabled = !hmsStore.getState(selectIsLocalAudioEnabled); await hmsActions.setLocalAudioEnabled(audioEnabled); muteAudio.textContent = audioEnabled ? "Mute" : "Unmute"; }; // Mute and unmute video muteVideo.onclick = async () => { const videoEnabled = !hmsStore.getState(selectIsLocalVideoEnabled); await hmsActions.setLocalVideoEnabled(videoEnabled); muteVideo.textContent = videoEnabled ? "Hide" : "Unhide"; }; // Showing the required elements on connection/disconnection function onConnection(isConnected) { if (isConnected) { form.classList.add("hide"); conference.classList.remove("hide"); leaveBtn.classList.remove("hide"); controls.classList.remove("hide"); } else { form.classList.remove("hide"); conference.classList.add("hide"); leaveBtn.classList.add("hide"); controls.classList.add("hide"); } } // Listen to the connection state hmsStore.subscribe(onConnection, selectIsConnectedToRoom);
Test the app
To test the application, run the application using:
- using Yarn
yarn parcel 100ms-test/index.html --port 3000
or - when using npm, run
npx parcel index.html --port 3000
.
This will start your development server in http://localhost:3000/. Open this in your browser to test the video conferencing app you created above.
Use room code to join the room
To test audio/video functionality, you need to connect to a 100ms room; please check following steps for the same:
- Navigate to your 100ms dashboard or create an account if you don't have one.
- Use the
Video Conferencing
template to create a room and test this app quickly. - Once the room is created, you will be shown a
Join Room
pop-up with options to join a room. Copy the room code shown in the pop-up. - Enter a user name and paste the room code copied in above step.
Now, after you click join
, you should be able to see yourself!
You can open the app in another tab in the browser to join as the second peer to check audio/video transactions between two or more peers.
We have a fully functional video conferencing application now 🎉🚀
Building step-by-step
In this section, let's walk through what the code does.
Initialize the SDK
Let us start with initializing the libraries. We need two instances to get started:
- An instance of HMSStore that holds 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.
- This HMSStore is a single source of truth for the entire SDK. To get access to the data from this store, you have to call hmsStore.subscribe(). It takes two parameters. A callback and a selector which tells the store which slice of state you want to subscribe to.
- The
subscribe()
also returns a reference tounsubscribe()
which could be used later to ubsubscribe from the subscription.
- And an instance of HMSActions that will help us perform actions such as joining the room, muting our audio, and sending messages.
import { HMSReactiveStore, selectIsLocalAudioEnabled, selectIsLocalVideoEnabled, selectPeers, selectIsConnectedToRoom } from "@100mslive/hms-video-store"; // Initialize HMS Store const hmsManager = new HMSReactiveStore(); hmsManager.triggerOnSubscribe(); const hmsStore = hmsManager.getStore(); const hmsActions = hmsManager.getHMSActions();
Initialize the HTML elements
Now, let's initialize all the HTML elements required such as tile for local and remote peers, join and leave button, mute and unmute button, etc.
// HTML elements const form = document.getElementById("join"); const joinBtn = document.getElementById("join-btn"); const conference = document.getElementById("conference"); const peersContainer = document.getElementById("peers-container"); const leaveBtn = document.getElementById("leave-btn"); const muteAudio = document.getElementById("mute-aud"); const muteVideo = document.getElementById("mute-vid"); const controls = document.getElementById("controls");
Join/leave 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 thepeer
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.
Let's use a form to request both of these fields from the user for our application.
Let's include a way for people to leave the room as well. To leave the room, we can use the hmsActions
leave method. We'll set up the leave
method to be called whenever the user closes the window or refreshes the tab.
// Joining the room joinBtn.onclick = async () => { const userName = document.getElementById("name").value const roomCode = document.getElementById("room-code").value // use room code to fetch auth token const authToken = await hmsActions.getAuthTokenByRoomCode({ roomCode }) // join room using username and auth token hmsActions.join({ userName, authToken }); }; // Leaving the room async function leaveRoom() { await hmsActions.leave(); peersContainer.innerHTML = ""; } // Cleanup if user refreshes the tab or navigates away window.onunload = window.onbeforeunload = leaveRoom; leaveBtn.onclick = leaveRoom;
Render video tiles for peers
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.
- We will use the attachVideo method on
hmsActions
to add the video from an element for a track ID. - And selectPeers selector from
hmsStore
// Helper function to create html elements function createElementWithClass(tag, className) { const newElement = document.createElement(tag); newElement.className = className; return newElement; } // Render a single peer function renderPeer(peer) { const peerTileDiv = createElementWithClass("div", "peer-tile"); const videoElement = createElementWithClass("video", "peer-video"); const peerTileName = createElementWithClass("span", "peer-name"); videoElement.autoplay = true; videoElement.muted = true; videoElement.playsinline = true; peerTileName.textContent = peer.name; hmsActions.attachVideo(peer.videoTrack, videoElement); peerTileDiv.append(videoElement); peerTileDiv.append(peerTileName); return peerTileDiv; } // Display a tile for each peer in the peer list function renderPeers() { peersContainer.innerHTML = ""; const peers = hmsStore.getState(selectPeers); peers.forEach((peer) => { if (peer.videoTrack) { peersContainer.append(renderPeer(peer)); } }); } // Reactive state - renderPeers is called whenever there is a change in the peer-list hmsStore.subscribe(renderPeers, selectPeers);
Mute/unmute 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 setLocalAudioEnabled method on hmsActions
to mute/unmute the local audio tracks and setLocalVideoEnabled method on hmsActions
to mute/unmute the local video tracks.
// Mute and unmute audio muteAudio.onclick = () => { const audioEnabled = !hmsStore.getState(selectIsLocalAudioEnabled); hmsActions.setLocalAudioEnabled(audioEnabled); muteAudio.textContent = audioEnabled ? "Mute" : "Unmute"; }; // Mute and unmute video muteVideo.onclick = () => { const videoEnabled = !hmsStore.getState(selectIsLocalVideoEnabled); hmsActions.setLocalVideoEnabled(videoEnabled); muteVideo.textContent = videoEnabled ? "Hide" : "Unhide"; // Re-render video tile renderPeers(); };
Change UI based on connection state
Right now, our join form will show up 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 from hmsStore
.
// Showing the required elements on connection/disconnection function onConnection(isConnected) { if (isConnected) { form.classList.add("hide"); conference.classList.remove("hide"); leaveBtn.classList.remove("hide"); controls.classList.remove("hide"); } else { form.classList.remove("hide"); conference.classList.add("hide"); leaveBtn.classList.add("hide"); controls.classList.add("hide"); } } // Listen to the connection state hmsStore.subscribe(onConnection, selectIsConnectedToRoom);
Refer to Test the app section above to test your sample app locally.
Next steps
Here's the complete example.
There is also a version of the above quickstart using our SDK from CDN directly. here.
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.
You can also check out our React demo app built with more features like screenshare, virtual background, noise suppression (deprecated), audio/video playlist, etc.