DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Creating a React Native SDK: Step-By-Step Guide With Practical Examples
  • Tracking Bugs Made Easy With React.js Bug Tracking Tools
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide

Trending

  • Ensuring Configuration Consistency Across Global Data Centers
  • Next-Gen IoT Performance Depends on Advanced Power Management ICs
  • Introduction to Retrieval Augmented Generation (RAG)
  • Event-Driven Architectures: Designing Scalable and Resilient Cloud Solutions
  1. DZone
  2. Coding
  3. JavaScript
  4. Building Scalable and Performant Live Streaming Apps With React and Video SDK

Building Scalable and Performant Live Streaming Apps With React and Video SDK

Learn how to create a powerful live streaming app with this step-by-step tutorial. Explore the seamless integration of React and a video SDK.

By 
Utpalsinh Parmar user avatar
Utpalsinh Parmar
·
Oct. 10, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
2.8K Views

Join the DZone community and get the full member experience.

Join For Free

Learn how to create a powerful live streaming app with this step-by-step tutorial. Explore the seamless integration of React and a video SDK to build an interactive live streaming experience. Follow along as we guide you through the development process, from setting up the environment to implementing key features such as real-time chat, live video streaming, and interactive engagement tools. Unlock the potential of React and a video SDK to create a captivating live streaming app that engages your audience like never before. Get started today and take your live streaming app development skills to the next level!

In today’s digital age, live streaming has become an increasingly popular medium for sharing content and engaging with audiences in real-time. With the rise of platforms like YouTube, Twitch, and Facebook Live, businesses and individuals alike are exploring ways to harness the power of live video to connect with their target audience. If you’re looking to build an interactive live streaming app using React and Video SDK, you’ve come to the right place. In this article, we’ll guide you through the process of creating a cutting-edge live streaming app that will help you stand out from the competition.

React has emerged as one of the most widely used JavaScript frameworks for building user interfaces. Its component-based architecture, virtual DOM, and efficient rendering make it a popular choice among developers. When combined with Video SDK, a powerful toolkit that provides developers with the necessary tools and functionalities for integrating live video streaming into their applications, React becomes an even more formidable force in the world of live streaming.

Tools for Building an Interactive Live Streaming App

  • VideoSDK.Live’s React SDK
  • VideoSDK.Live’s HLS Composition
  • VideoSDK.Live’s HLS Streaming

Four Steps To Build React Interactive Live Streaming App Using Video SDK

Step 1: Understanding Your Live Streaming App Functionalities and Project Structure

I will be creating this app for 2 types of users, Speaker and Viewer.

  • Speaker will have all media controls i.e. they can toggle their webcam and mic to share their information to the viewers. Speaker can also start HLS stream so that viewer consume the content.
  • Viewer will not have any media controls, they will just watch an VideoSDK HLS Stream, which was started by speaker

Prerequisites Before Starting To Write Code:

  • VideoSDK Account. If not, you can signup
  • Coding environment for React
  • Good understanding of React

After our coding environment is setup, we can now start writing our code, first I will create a new React App using create-react-app, also we will install useful dependencies.

npx create-react-app videosdk-interactive-live-streaming-app
cd videosdk-interactive-live-streaming-app
npm install @videosdk.live/react-sdk react-player hls.js


Project Structure

I will create three screens:

  1. Welcome Screen
  2. Speaker Screen
  3. Viewer Screen

Below is the folder structure of our app.

root/
├──node_modules/
├──public/
├──src/
├────screens/
├───────WelcomeScreenContainer.js
├───────speakerScreen/
├──────────MediaControlsContainer.js
├──────────ParticipantsGridContainer.js
├──────────SingleParticipantContainer.js
├──────────SpeakerScreenContainer.js
├──────ViewerScreenContainer.js
├────api.js
├────App.js
├────index.js


App Container

I will prepare a basic App.js, This file will contain all the screens and render all of them conditionally according to the appData state changes.

/src/App.js

import React, { useState } from "react";
import SpeakerScreenContainer from "./screens/speakerScreen/SpeakerScreenContainer";
import ViewerScreenContainer from "./screens/ViewerScreenContainer";
import WelcomeScreenContainer from "./screens/WelcomeScreenContainer";
const App = () => {
  const [appData, setAppData] = useState({ meetingId: null, mode: null });
  return appData.meetingId ? (
    appData.mode === "CONFERENCE" ? (
      <SpeakerScreenContainer meetingId={appData.meetingId} />
    ) : (
      <ViewerScreenContainer meetingId={appData.meetingId} />
    )
  ) : (
    <WelcomeScreenContainer setAppData={setAppData} />
  );
};
export default App;


Step 2: Welcome Screen of Your React Live Streaming App

Creating a new meeting will require an API call, so we will write some code for that

A temporary auth-token can be fetched from our user dashboard, but in production, we recommend to use an auth-token generated by your servers.

Follow this guide to get temporary auth-token from user dashboard.

/src/api.js

JavaScript
 
export const authToken = "temporary-generated-auth-token-goes-here";


JavaScript
 
export const createNewRoom = async () => {
  const res = await fetch(`https://api.videosdk.live/v2/rooms`, {
    method: "POST",
    headers: {
      authorization: `${authToken}`,
      "Content-Type": "application/json",
    },
  });
  const { roomId } = await res.json();
  return roomId;
};


WelcomeScreenContainer will be useful for creating a new meeting by speakers. it will also allow to enter already created meetingId to join the existing session.
src/screens/WelcomeScreenContainer.js

JavaScript
 
import React, { useState } from "react";
import { createNewRoom } from "../api";


JavaScript
 
const WelcomeScreenContainer = ({ setAppData }) => {
  const [meetingId, setMeetingId] = useState("");
  const createClick = async () => {
    const meetingId = await createNewRoom();
    setAppData({ mode: "CONFERENCE", meetingId });
  };
  const hostClick = () => setAppData({ mode: "CONFERENCE", meetingId });
  const viewerClick = () => setAppData({ mode: "VIEWER", meetingId });
  return (
    <div>
      <button onClick={createClick}>Create new Meeting</button>
      <p>{"\n\nor\n\n"}</p>
      <input
        placeholder="Enter meetingId"
        onChange={(e) => setMeetingId(e.target.value)}
        value={meetingId}
      />
      <p>{"\n\n"}</p>
      <button onClick={hostClick}>Join As Host</button>
      <button onClick={viewerClick}>Join As Viewer</button>
    </div>
  );
};
export default WelcomeScreenContainer;


Step 3: Speaker Screen

This screen will contain all the media controls and participants grid. First I will create a name input box for participant who will be joining.
src/screens/speakerScreen/SpeakerScreenContainer.js

JavaScript
 
import { MeetingProvider } from "@videosdk.live/react-sdk";
import React from "react";
import MediaControlsContainer from "./MediaControlsContainer";
import ParticipantsGridContainer from "./ParticipantsGridContainer";


JavaScript
 
import { authToken } from "../../api";
const SpeakerScreenContainer = ({ meetingId }) => {
  return (
    <MeetingProvider
      token={authToken}
      config={{
        meetingId,
        name: "C.V. Raman",
        micEnabled: true,
        webcamEnabled: true,
      }}
      joinWithoutUserInteraction
    >
      <MediaControlsContainer meetingId={meetingId} />
      <ParticipantsGridContainer />
    </MeetingProvider>
  );
};
export default SpeakerScreenContainer;


MediaControls

This container will be used for toggling mic and webcam. Also, we will add some code for starting HLS streaming.

JavaScript
 
import { useMeeting, Constants } from "@videosdk.live/react-sdk";
import React, { useMemo } from "react";


JavaScript
 
const MediaControlsContainer = () => {
  const { toggleMic, toggleWebcam, startHls, stopHls, hlsState, meetingId } =
    useMeeting();
  const { isHlsStarted, isHlsStopped, isHlsPlayable } = useMemo(
    () => ({
      isHlsStarted: hlsState === Constants.hlsEvents.HLS_STARTED,
      isHlsStopped: hlsState === Constants.hlsEvents.HLS_STOPPED,
      isHlsPlayable: hlsState === Constants.hlsEvents.HLS_PLAYABLE,
    }),
    [hlsState]
  );
  const _handleToggleHls = () => {
    if (isHlsStarted) {
      stopHls();
    } else if (isHlsStopped) {
      startHls({ quality: "high" });
    }
  };
  return (
    <div>
      <p>MeetingId: {meetingId}</p>
      <p>HLS state: {hlsState}</p>
      {isHlsPlayable && <p>Viewers will now be able to watch the stream.</p>}
      <button onClick={toggleMic}>Toggle Mic</button>
      <button onClick={toggleWebcam}>Toggle Webcam</button>
      <button onClick={_handleToggleHls}>
        {isHlsStarted ? "Stop Hls" : "Start Hls"}
      </button>
    </div>
  );
};
export default MediaControlsContainer;


ParticipantGridContainer

This will get all the joined participants from useMeeting hook and render them individually. Here we will be using SingleParticipantContainer for rendering a single participant's webcam stream.
src/screens/speakerScreen/ParticipantsGridContainer.js

JavaScript
 
import { useMeeting } from "@videosdk.live/react-sdk";
import React, { useMemo } from "react";
import SingleParticipantContainer from "./SingleParticipantContainer";


JavaScript
 
const ParticipantsGridContainer = () => {
  const { participants } = useMeeting();
  const participantIds = useMemo(
    () => [...participants.keys()],
    [participants]
  );
  return (
    <div>
      {participantIds.map((participantId) => (
        <SingleParticipantContainer
          {...{ participantId, key: participantId }}
        />
      ))}
    </div>
  );
};
export default ParticipantsGridContainer;


SingleParticipantContainer

This container will get participantId from props and will get webcam streams and other information from useParticipant hook.
It will render both Audio and Video streams of the participant whose participantId is provided from props.
src/screens/speakerScreen/SingleParticipantContainer.js

JavaScript
 
import { useParticipant } from "@videosdk.live/react-sdk";
import React, { useEffect, useMemo, useRef } from "react";
import ReactPlayer from "react-player";


JavaScript
 
const SingleParticipantContainer = ({ participantId }) => {
  const { micOn, micStream, isLocal, displayName, webcamStream, webcamOn } =
    useParticipant(participantId);
  const audioPlayer = useRef();
  const videoStream = useMemo(() => {
    if (webcamOn && webcamStream) {
      const mediaStream = new MediaStream();
      mediaStream.addTrack(webcamStream.track);
      return mediaStream;
    }
  }, [webcamStream, webcamOn]);
  useEffect(() => {
    if (!isLocal && audioPlayer.current && micOn && micStream) {
      const mediaStream = new MediaStream();
      mediaStream.addTrack(micStream.track);
      audioPlayer.current.srcObject = mediaStream;
      audioPlayer.current.play().catch((err) => {
        if (
          err.message ===
          "play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD"
        ) {
          console.error("audio" + err.message);
        }
      });
    } else {
      audioPlayer.current.srcObject = null;
    }
  }, [micStream, micOn, isLocal, participantId]);
  return (
    <div style={{ height: 200, width: 360, position: "relative" }}>
      <audio autoPlay playsInline controls={false} ref={audioPlayer} />
      <div
        style={{ position: "absolute", background: "#ffffffb3", padding: 8 }}
      >
        <p>Name: {displayName}</p>
        <p>Webcam: {webcamOn ? "on" : "off"}</p>
        <p>Mic: {micOn ? "on" : "off"}</p>
      </div>
      {webcamOn && (
        <ReactPlayer
          playsinline // very very imp prop
          pip={false}
          light={false}
          controls={false}
          muted={true}
          playing={true}
          url={videoStream}
          height={"100%"}
          width={"100%"}
          onError={(err) => {
            console.log(err, "participant video error");
          }}
        />
      )}
    </div>
  );
};
export default SingleParticipantContainer;


Our speaker screen is completed, not we can start coding ViewerScreenContainer

Step 4: Viewer Screen

Viewer screen will be used for viewer participants, they will be watching the HLS stream when speaker starts to stream.
Same as Speaker screen this screen will also have initialization process.
src/screens/ViewerScreenContainer.js

JavaScript
 
import {
  MeetingConsumer,
  Constants,
  MeetingProvider,
  useMeeting,
} from "@videosdk.live/react-sdk";
import React, { useEffect, useMemo, useRef } from "react";
import Hls from "hls.js";
import { authToken } from "../api";


JavaScript
 
const HLSPlayer = () => {
  const { hlsUrls, hlsState } = useMeeting();
  const playerRef = useRef(null);
  const hlsPlaybackHlsUrl = useMemo(() => hlsUrls.playbackHlsUrl, [hlsUrls]);
  useEffect(() => {
    if (Hls.isSupported()) {
      const hls = new Hls({
        capLevelToPlayerSize: true,
        maxLoadingDelay: 4,
        minAutoBitrate: 0,
        autoStartLoad: true,
        defaultAudioCodec: "mp4a.40.2",
      });
      let player = document.querySelector("#hlsPlayer");
      hls.loadSource(hlsPlaybackHlsUrl);
      hls.attachMedia(player);
    } else {
      if (typeof playerRef.current?.play === "function") {
        playerRef.current.src = hlsPlaybackHlsUrl;
        playerRef.current.play();
      }
    }
  }, [hlsPlaybackHlsUrl, hlsState]);
  return (
    <video
      ref={playerRef}
      id="hlsPlayer"
      autoPlay
      controls
      style={{ width: "70%", height: "70%" }}
      playsInline
      playing
      onError={(err) => console.log(err, "hls video error")}
    ></video>
  );
};
const ViewerScreenContainer = ({ meetingId }) => {
  return (
    <MeetingProvider
      token={authToken}
      config={{ meetingId, name: "C.V. Raman", mode: "VIEWER" }}
      joinWithoutUserInteraction
    >
      <MeetingConsumer>
        {({ hlsState }) =>
          hlsState === Constants.hlsEvents.HLS_PLAYABLE ? (
            <HLSPlayer />
          ) : (
            <p>Waiting for host to start stream...</p>
          )
        }
      </MeetingConsumer>
    </MeetingProvider>
  );
};
export default ViewerScreenContainer;


Our ViewerScreen is completed, now we can test our application.
npm run start

Output of Interactive Live Streaming App

Source Code of this app is available in this GithubRepo.

What Next?

This was a very basic example of interactive Live Streaming App using Video SDK, you can customize it in your way.

  • Add more CSS to make the UI more interactive
  • Add Chat using PubSub
  • Implement Change Mode, by this we can switch any participant from Viewer to Speaker, or vice versa.
  • You can also take reference from our Prebuilt App which is build using VideoSDK’s React package. Here is the Github Repo.

More React Resources

  • React Video Call Quick Start Docs
  • React Interactive Live Streaming Quick Start Docs
  • Build a Video Chat App with React Hooks
  • Code Samples

Conclusion

With this, we successfully built the React Interactive Live Streaming app with video SDK. You can always refer to our documentations. if you want to add features like chat messaging and screen sharing. If you have any problem with the implementation, Please contact us via our Discord community.

Don’t forget to share this article on Twitter.

JavaScript Software development kit React (JavaScript library)

Published at DZone with permission of Utpalsinh Parmar. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Creating a React Native SDK: Step-By-Step Guide With Practical Examples
  • Tracking Bugs Made Easy With React.js Bug Tracking Tools
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: