Skip to main content
Version: 0.0.x

Quick Start for Interactive Live Streaming in Javascript

VideoSDK empowers you to seamlessly integrate interactive live streaming features into your JavaScript application in minutes. While built for meetings, the SDK is easily adaptable for live streaming with support for up to 100 hosts/co-hosts and 2,000 viewers in real-time. Perfect for social use cases, this guide will walk you through integrating live streaming into your app.

info

For standard live streaming with 6-7 second latency and playback support, follow this documentation.

Prerequisites​

Before proceeding, ensure that your development environment meets the following requirements:

  • Video SDK Developer Account (Not having one, follow Video SDK Dashboard)
  • Have Node and NPM installed on your device.

Getting Started with the Code!​

Follow the steps to create the environment necessary to add live streaming into your app. You can also find the code sample for quickstart here.

Install Video SDK​

Import VideoSDK using the <script> tag or Install it using the following npm command. Make sure you are in your app directory before you run this command.

<html>
<head>
<!--.....-->
</head>
<body>
<!--.....-->
<script src="https://sdk.videosdk.live/js-sdk/0.1.4/videosdk.js"></script>
</body>
</html>

Structure of the project​

Your project structure should look like this.

  root
├── index.html
├── config.js
├── index.js

You will be working on the following files:

  • index.html: Responsible for creating a basic UI.
  • config.js: Responsible for storing the token.
  • index.js: Responsible for rendering the Host and Audience view and the join stream functionality.

Step 1: Design the user interface (UI)​

The HTML document consists of two main sections: the Join Screen for users to create or join a live stream, and the Grid Screen for displaying the live stream and controls.

<!DOCTYPE html>
<html>
<head>
<style>
/* Basic body styles */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background: #fff;
}
/* Styles for the main screens */
#join-screen,
#grid-screen {
background: #e9e9e9;
border: 1px solid #ccc;
padding: 15px;
margin: 15px 0;
}
/* Common styles for buttons and input fields */
button,
input[type="text"] {
margin: 5px;
}
/* Button styles */
button {
background: #007bff;
color: #fff;
border: none;
padding: 8px;
cursor: pointer;
}
/* Button hover effect */
button:hover {
background: #0056b3;
}
/* Input field styles */
input[type="text"] {
padding: 8px;
border: 1px solid #aaa;
width: calc(100% - 16px);
}
/* Control button layout */
#controls {
display: flex;
}
</style>
</head>
<body>
<!-- Join screen for creating or joining live streams -->
<div id="join-screen">
<button id="createLiveStreamBtn">Create Live Stream As Host</button>
<div><span>OR</span></div>
<input type="text" id="streamIdText" placeholder="Enter Stream Id" />
<div>
<button id="joinHostBtn">Join As Host</button>
<button id="joinAudienceBtn">Join As Audience</button>
</div>
</div>

<!-- Placeholder for text messages -->
<div id="textDiv"></div>

<!-- Grid screen for video and controls, hidden by default -->
<div id="grid-screen" style="display: none">
<h3 id="heading"></h3>
<div id="controls">
<button id="leaveBtn">Leave</button>
<button id="toggleMicBtn" style="display: none">Toggle Mic</button>
<button id="toggleWebCamBtn" style="display: none">Toggle Cam</button>
<button id="switchModeBtn"></button>
</div>
<div id="videoContainer"></div>
</div>

<!-- Script imports -->
<script src="https://sdk.videosdk.live/js-sdk/0.1.4/videosdk.js"></script>
<script src="config.js"></script>
<script src="index.js"></script>
</body>
</html>

Output​

Step 2: Implement Join Screen​

Configure the token in the config.js file, which you can obtain from the VideoSDK Dashboard.

// Auth token will be used to generate a streamId and connect to it
TOKEN = "Your_Token_Here";

Next, retrieve all the elements from the DOM and declare the following variables in the index.js file. Then, add an event listener to the join and create Live Stream buttons.

Before proceeding, let's understand the two modes of a Live Stream:

1. SEND_AND_RECV (For Host or Co-host):​

  • Designed primarily for the Host or Co-host.
  • Allows sending and receiving media.
  • Hosts can broadcast their audio/video and interact directly with the audience.

2. RECV_ONLY (For Audience):​

  • Tailored for the Audience.
  • Enables receiving media shared by the Host.
  • Audience members can view and listen but cannot share their own media.
ILS Mode Demonstration

The join screen will serve as a medium to either create a new Live Stream or join an existing one as a host or an audience.

This functionality includes three action buttons for joining or creating a Live Stream:

  1. Join as Host: Allows the user to join an existing Live Stream using the provided streamId with the SEND_AND_RECV mode, enabling full host privileges.

  2. Join as Audience: Enables the user to join an existing Live Stream using the provided streamId with the RECV_ONLY mode, allowing view-only access.

  3. Create Live Stream as Host: Lets the user initiate a new Live Stream in SEND_AND_RECV mode, granting full host controls.

// getting Elements from Dom
const elements = {
createLiveStreamBtn: document.getElementById("createLiveStreamBtn"),
joinHostButton: document.getElementById("joinHostBtn"),
joinAudienceButton: document.getElementById("joinAudienceBtn"),
leaveButton: document.getElementById("leaveBtn"),
toggleMicButton: document.getElementById("toggleMicBtn"),
toggleWebCamButton: document.getElementById("toggleWebCamBtn"),
videoContainer: document.getElementById("videoContainer"),
textDiv: document.getElementById("textDiv"),
switchModeBtn: document.getElementById("switchModeBtn"),
};

// declare Variables
let liveStream = null;
let streamId = "";
let isMicOn = false;
let isWebCamOn = false;

const Constants = VideoSDK.Constants;

// Will implement this method in next step
function initializeLiveStream(mode) {
console.log("Mode", mode);
}

// Create Live Stream Button Event Listener
elements.createLiveStreamBtn.addEventListener("click", async () => {
await createLiveStream();
});

// Join Live Stream As Host Button Event Listener
elements.joinHostButton.addEventListener("click", async () => {
await joinLiveStream(Constants.modes.SEND_AND_RECV);
});

// Join Live Stream As Viewer Button Event Listener
elements.joinAudienceButton.addEventListener("click", async () => {
await joinLiveStream(Constants.modes.RECV_ONLY);
});

// Helper functions for live stream creation and joining
async function createLiveStream() {
document.getElementById("join-screen").style.display = "none";
elements.textDiv.textContent = "Creating new Live Stream...";
const { roomId } = await fetchLiveStreamRoom();
streamId = roomId;
initializeLiveStream(Constants.modes.SEND_AND_RECV);
}

async function joinLiveStream(mode) {
const roomId = document.getElementById("streamIdText").value;
if (!roomId) return alert("Please enter Stream Id");
document.getElementById("join-screen").style.display = "none";
elements.textDiv.textContent = `Joining the Live Stream as ${
mode === Constants.modes.SEND_AND_RECV ? "host" : "audience"
}...`;
streamId = roomId;
initializeLiveStream(mode);
}

async function fetchLiveStreamRoom() {
const url = `https://api.videosdk.live/v2/rooms`;
const options = {
method: "POST",
headers: { Authorization: TOKEN, "Content-Type": "application/json" },
};
return await fetch(url, options)
.then((response) => response.json())
.catch((error) => alert("error", error));
}

Step 3: Initialize and Join the Live Stream​

This step configures the live stream with VideoSDK, sets up event handlers for participant actions, and updates UI controls dynamically based on the participant's mode (host or audience). Key functionalities include initializing the live stream, managing events (join, leave, mode change), and ensuring mode-specific UI adjustments.

// Initialize live stream
function initializeLiveStream(mode) {
window.VideoSDK.config(TOKEN);
liveStream = window.VideoSDK.initMeeting({
meetingId: streamId,
name: "Thomas Edison",
webcamEnabled: true,
micEnabled: true,
mode: mode,
});

liveStream.join();
setupLiveStreamEventHandlers(mode);
}

// Function to update controls visibility
function updateControlsVisibility(mode) {
const isHost = mode === Constants.modes.SEND_AND_RECV;
elements.toggleMicButton.style.display = isHost ? "inline-block" : "none";
elements.toggleWebCamButton.style.display = isHost ? "inline-block" : "none";
elements.switchModeBtn.textContent = isHost
? "Switch to Audience Mode"
: "Switch to Host Mode";
}

function setupLiveStreamEventHandlers(mode) {
liveStream.on("meeting-joined", () => handleLiveStreamJoined(mode));
liveStream.on("meeting-left", () => (elements.videoContainer.innerHTML = ""));
liveStream.on("participant-joined", handleParticipantJoined);
liveStream.on("participant-left", handleParticipantLeft);
liveStream.on("participant-mode-changed", handleParticipantModeChange);
}

function handleLiveStreamJoined(mode) {
elements.textDiv.textContent = null;
document.getElementById("grid-screen").style.display = "block";
document.getElementById("heading").textContent = `Stream Id: ${streamId}`;
updateControlsVisibility(mode);
}

function handleParticipantJoined(participant) {}

function handleParticipantLeft(participant) {}

function handleParticipantModeChange(data) {}

Output​

Step 4: Manage Media Elements​

This step sets up video and audio elements for participants, including creating video frames with participant names and handling media tracks. It also initializes the local participant's video and manages audio and video streams dynamically.

// creating video element
function createVideoElement(pId, name) {
const videoFrame = document.createElement("div");
videoFrame.id = `f-${pId}`;
const videoElement = document.createElement("video");
videoElement.classList.add("video-frame");
videoElement.id = `v-${pId}`;
videoElement.playsInline = true;
videoElement.width = 300;
videoFrame.append(videoElement, createDisplayNameElement(name));
return videoFrame;
}

function createDisplayNameElement(name) {
const displayName = document.createElement("div");
displayName.innerHTML = `Name : ${name}`;
return displayName;
}

// creating audio element
function createAudioElement(pId) {
const audioElement = document.createElement("audio");
audioElement.id = `a-${pId}`;
audioElement.autoPlay = false;
audioElement.playsInline = true;
audioElement.controls = false;
audioElement.style.display = "none";
return audioElement;
}

// creating local participant
function createLocalParticipant() {
const localParticipant = createVideoElement(
liveStream.localParticipant.id,
liveStream.localParticipant.displayName
);
elements.videoContainer.appendChild(localParticipant);
}

// setting media track
function setTrack(stream, audioElement, participant, isLocal) {
const mediaStream = new MediaStream();
mediaStream.addTrack(stream.track);
if (stream.kind === "video") {
isWebCamOn = true;
const videoElm = document.getElementById(`v-${participant.id}`);
videoElm.srcObject = mediaStream;
videoElm
.play()
.catch((error) => console.error("videoElem.play() failed", error));
} else if (stream.kind === "audio") {
if (isLocal) isMicOn = true;
audioElement.srcObject = mediaStream;
audioElement
.play()
.catch((error) => console.error("audioElem.play() failed", error));
}
}

Step 5: Handle participant events​

This step handles participant events, distinguishing between Host (SEND_AND_RECV) and Audience (RECV_ONLY) modes. It dynamically manages media elements, ensuring Hosts can send/receive streams while the Audience can only view/listen. Events for joining, leaving, or mode changes update streams in real-time.

function handleLiveStreamJoined(mode) {
//...
// Existing code
if (mode === Constants.modes.SEND_AND_RECV) {
createLocalParticipant();
liveStream.localParticipant.on("stream-enabled", (stream) =>
setTrack(stream, null, liveStream.localParticipant, true)
);
}
}
function handleParticipantModeChange(data) {
const { mode, participantId } = data;
const isLocal = liveStream.localParticipant.id === participantId;
if (isLocal) {
updateControlsVisibility(mode);
if (mode === Constants.modes.SEND_AND_RECV) {
createLocalParticipant();
liveStream.localParticipant.on("stream-enabled", (stream) =>
setTrack(stream, null, liveStream.localParticipant, true)
);
} else {
removeLocalVideo();
}
} else {
if (mode === Constants.modes.SEND_AND_RECV) {
const participant = liveStream.participants.get(participantId);
if (participant) {
// Ensure video and audio elements are re-created
const videoElement = createVideoElement(
participant.id,
participant.displayName
);
const audioElement = createAudioElement(participant.id);

participant.on("stream-enabled", (stream) =>
setTrack(stream, audioElement, participant, false)
);
// Append to the container
elements.videoContainer.append(videoElement, audioElement);
}
} else {
removeParticipantMedia(participantId);
}
}
}
function handleParticipantJoined(participant) {
if (participant.mode === Constants.modes.SEND_AND_RECV) {
const videoElement = createVideoElement(
participant.id,
participant.displayName
);
const audioElement = createAudioElement(participant.id);
participant.on("stream-enabled", (stream) =>
setTrack(stream, audioElement, participant, false)
);
elements.videoContainer.append(videoElement, audioElement);
}
}
function handleParticipantLeft(participant) {
removeParticipantMedia(participant.id);
}
function removeLocalVideo() {
const localVideo = document.getElementById(
`f-${liveStream.localParticipant.id}`
);
if (localVideo) localVideo.remove();
}
function removeParticipantMedia(participantId) {
document.getElementById(`f-${participantId}`)?.remove();
document.getElementById(`a-${participantId}`)?.remove();
}

Output​

Step 6: Add Live Stream Controls​

Implement interactive controls to leave the live stream, toggle microphone and webcam, and switch between Host (SEND_AND_RECV) and Audience (RECV_ONLY) modes for a seamless experience.

// leave Live Stream Button Event Listener
elements.leaveButton.addEventListener("click", () => {
liveStream?.leave();
document.getElementById("grid-screen").style.display = "none";
document.getElementById("join-screen").style.display = "block";
});

// Toggle Mic Button Event Listener
elements.toggleMicButton.addEventListener("click", () => {
isMicOn ? liveStream?.muteMic() : liveStream?.unmuteMic();
isMicOn = !isMicOn;
});

// Toggle Web Cam Button Event Listener
elements.toggleWebCamButton.addEventListener("click", () => {
isWebCamOn ? liveStream?.disableWebcam() : liveStream?.enableWebcam();
const vElement = document.getElementById(
`f-${liveStream.localParticipant.id}`
);
if (vElement) vElement.style.display = isWebCamOn ? "none" : "inline";
isWebCamOn = !isWebCamOn;
});

// Update switch mode button handler
elements.switchModeBtn.addEventListener("click", () => {
const newMode =
liveStream.localParticipant.mode === Constants.modes.SEND_AND_RECV
? Constants.modes.RECV_ONLY
: Constants.modes.SEND_AND_RECV;
liveStream.changeMode(newMode);
});

Final Output​

tip

You can checkout the complete quick start example here.

Got a Question? Ask us on discord