video sdk logo

Login

React Audio Room Tutorial

Build Clubhouse-style audio rooms with low-latency spatial audio, speaker/listener roles, and real-time moderation controls.
React Audio Room Tutorial

Trusted by 300+ global business & tech leaders

Build an Audio-Only Room in React, Step by Step

Learn how to build an audio-only room in React using the VideoSDK React SDK. This tutorial covers room setup, speaker and listener roles, participant state, and moderation controls from blank project to live session.


Prerequisites

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

  • VideoSDK Developer Account (Not having one, follow VideoSDK Dashboard)
  • Basic understanding of React
  • React VideoSDK
  • Have Node and NPM installed on your device.
  • Basic understanding of Hooks (useState, useRef, useEffect)
  • React Context API (optional)

Important: One should have a VideoSDK account to generate token. Visit VideoSDK dashboard to generate token

Getting Started with the Code!

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

Create new React App

Create a new React App using the below command.

Terminal
1npm create vite@latest videosdk-rtc-react-app -- --template react
2

Install VideoSDK

Install the VideoSDK using the below-mentioned npm command. Make sure you are in your react app directory before you run this command.

NPM
1npm install "@videosdk.live/react-sdk"
2
Yarn
1yarn add "@videosdk.live/react-sdk"
2

Structure of the project

Your project structure should look like this.

Project Structure
1   root
2   ├── node_modules
3   ├── public
4   ├── src
5   │    ├── API.js
6   │    ├── App.jsx
7   │    ├── main.jsx
8   .    .
9

You are going to use functional components to leverage react's reusable component architecture. There will be components for users and controls (mic, leave).

App Architecture

The App will contain a MeetingView component which includes a ParticipantView component which will render the participant's name and audio. It will also have a Controls component which will allow the user to perform operations like leave and toggle the microphone.

You will be working on the following files:

  • API.js: Responsible for handling API calls such as generating unique meetingId and token
  • App.jsx: Responsible for rendering MeetingView and joining the meeting.

Step 1: Get started with API.js

Prior to moving on, you must create an API request to generate a unique meetingId. You will need an authentication token, which you can create either through the videosdk-rtc-api-server-examples or directly from the VideoSDK Dashboard for developers.

API.js (Javascript)
1// Generate your token at https://app.videosdk.live/api-keys and paste it below.
2export const authToken = "";
3
4// API call to create meeting
5export const createMeeting = async ({ token }) => {
6  try {
7    const res = await fetch(`https://api.videosdk.live/v2/rooms`, {
8      method: "POST",
9      headers: {
10        authorization: `${token}`,
11        "Content-Type": "application/json",
12      },
13      body: JSON.stringify({}),
14    });
15
16    if (!res.ok) {
17      throw new Error(`Failed to create meeting: ${res.status}`);
18    }
19
20    //Destructuring the roomId from the response
21    const { roomId } = await res.json();
22    return roomId;
23  } catch (error) {
24    console.error("createMeeting failed", error);
25    throw error;
26  }
27};
28

Step 2: Wireframe App.jsx with all the components

To build up wireframe of App.jsx, you need to use VideoSDK Hooks and Context Providers. VideoSDK provides MeetingProvider, MeetingConsumer, useMeeting and useParticipant hooks.

First you need to understand Context Provider and Consumer. Context is primarily used when some data needs to be accessible by many components at different nesting levels.

  • MeetingProvider: This is the Context Provider. It accepts value config and token as props. The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.
  • MeetingConsumer: This is the Context Consumer. All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
  • useMeeting: This is the meeting hook API. It includes all the information related to meeting such as join, leave, enable/disable mic etc.
  • useParticipant: This is the participant hook API. It is responsible for handling all the events and props related to one particular participant such as name, micStream etc.

The Meeting Context provides a way to listen for any changes that occur when a participant joins the meeting or makes modifications to their microphone and other settings. Begin by making a few changes to the code in the App.jsx file.

Since this is an audio only call, pass webcamEnabled: false in the MeetingProvider config so the participant publishes the microphone alone and the browser never asks for camera permission.

App.jsx (Javascript)
1import "./App.css";
2import React, { useEffect, useMemo, useRef, useState } from "react";
3import {
4  MeetingProvider,
5  MeetingConsumer,
6  useMeeting,
7  useParticipant,
8} from "@videosdk.live/react-sdk";
9import { authToken, createMeeting } from "./API";
10
11function JoinScreen({ getMeetingAndToken }) {
12  return null;
13}
14
15function ParticipantView(props) {
16  return null;
17}
18
19function Controls(props) {
20  return null;
21}
22
23function MeetingView(props) {
24  return null;
25}
26
27function App() {
28  const [meetingId, setMeetingId] = useState(null);
29
30  //Getting the meeting id by calling the api we just wrote
31  const getMeetingAndToken = async (id) => {
32  if (!authToken) {
33      console.error("PLEASE PROVIDE TOKEN IN API.js FROM app.videosdk.live");
34      return;
35    }
36    const meetingId =
37      id == null ? await createMeeting({ token: authToken }) : id;
38    setMeetingId(meetingId);
39  };
40
41  //This will set Meeting Id to null when meeting is left or ended
42  const onMeetingLeave = () => {
43    setMeetingId(null);
44  };
45
46  return authToken && meetingId ? (
47    <MeetingProvider
48      config={{
49        meetingId,
50        micEnabled: true,
51        webcamEnabled: false, // audio only call, so the camera stays off
52        name: "C.V. Raman",
53      }}
54      token={authToken}
55    >
56      <MeetingConsumer>
57        {() => (
58          <MeetingView meetingId={meetingId} onMeetingLeave={onMeetingLeave} />
59        )}
60      </MeetingConsumer>
61    </MeetingProvider>
62  ) : (
63    <JoinScreen getMeetingAndToken={getMeetingAndToken} />
64  );
65}
66
67export default App;
68

Step 3: Implement Join Screen

Join screen will serve as a medium to either schedule a new meeting or join an existing one.

JoinScreen Component (Javascript)
1function JoinScreen({ getMeetingAndToken }) {
2  const [meetingId, setMeetingId] = useState(null);
3  const onClick = async () => {
4    await getMeetingAndToken(meetingId);
5  };
6  return (
7    <div>
8      <input
9        type="text"
10        placeholder="Enter Meeting Id"
11        onChange={(e) => {
12          setMeetingId(e.target.value);
13        }}
14      />
15      <button onClick={onClick}>Join</button>
16      {" or "}
17      <button onClick={onClick}>Create Meeting</button>
18    </div>
19  );
20}
21

Output

VideoSDK React JS Quick Start Join Screen

Step 4: Implement MeetingView and Controls

Next step is to create MeetingView and Controls components to manage features such as join, leave, mute and unmute.

From v1.0.0, all these methods are asynchronous and return a Promise, so awaitthem and handle failures with try / catch. For details, see the Migration Guide.

MeetingView (Javascript)
1function MeetingView(props) {
2  const [joined, setJoined] = useState(null);
3  //Get the method which will be used to join the meeting.
4  //We will also get the participants list to display all participants
5  const { join, participants } = useMeeting({
6    //callback for when meeting is joined successfully
7    onMeetingJoined: () => {
8      setJoined("JOINED");
9    },
10    //callback for when meeting is left
11    onMeetingLeft: () => {
12      props.onMeetingLeave();
13    },
14  });
15  const joinMeeting = () => {
16    setJoined("JOINING");
17    join();
18  };
19
20  return (
21    <div className="container">
22      <h3>Meeting Id: {props.meetingId}</h3>
23      {joined && joined == "JOINED" ? (
24        <div>
25          <Controls />
26          //For rendering all the participants in the meeting
27          {[...participants.keys()].map((participantId) => (
28            <ParticipantView
29              participantId={participantId}
30              key={participantId}
31            />
32          ))}
33        </div>
34      ) : joined && joined == "JOINING" ? (
35        <p>Joining the meeting...</p>
36      ) : (
37        <button onClick={joinMeeting}>Join</button>
38      )}
39    </div>
40  );
41}
42
Controls Component (Javascript)
1function Controls() {
2  const { leave, toggleMic } = useMeeting();
3
4  const handleLeave = async () => {
5    try {
6      await leave();
7    } catch (error) {
8      console.error("Failed to leave meeting", error);
9    }
10  };
11
12  const handleToggleMic = async () => {
13    try {
14      await toggleMic();
15    } catch (error) {
16      console.error("Failed to toggle mic", error);
17    }
18  };
19
20  return (
21    <div>
22      <button onClick={handleLeave}>Leave</button>
23      <button onClick={handleToggleMic}>toggleMic</button>
24    </div>
25  );
26}
27

Step 5: Implement Participant View

Before implementing the participant view, you need to understand a couple of concepts.

1. Forwarding Ref for mic

The useRef hook is responsible for referencing the audio component. It will be used to play and stop the audio of the participant.

Forwarding Ref for mic
1const micRef = useRef(null);
2

2. useParticipant Hook

The useParticipant hook is responsible for handling all the properties and events of one particular participant joined in the meeting. It will take participantId as argument.

useParticipant Hook
1const { micStream, micOn } = useParticipant(props.participantId);
2

3. MediaStream API

The MediaStream API is beneficial for adding a MediaTrack to the audio tag, enabling the playback of audio.

MediaStream API
1const micRef = useRef(null);
2const mediaStream = new MediaStream();
3mediaStream.addTrack(micStream.track);
4
5micRef.current.srcObject = mediaStream;
6micRef.current
7  .play()
8  .catch((error) => console.error("micElem.current.play() failed", error));
9

Note: The MediaStream API is what attaches the participant's microphone track to the <audio> element. The local participant's audio element is muted so you do not hear your own echo.

Now you can use both of the hooks and the API to create ParticipantView

ParticipantView (Javascript)
1function ParticipantView(props) {
2  const micRef = useRef(null);
3  const { micStream, micOn, isLocal, displayName } =
4    useParticipant(props.participantId);
5
6  useEffect(() => {
7    if (micRef.current) {
8      if (micOn && micStream) {
9        const mediaStream = new MediaStream();
10        mediaStream.addTrack(micStream.track);
11
12        micRef.current.srcObject = mediaStream;
13        micRef.current
14          .play()
15          .catch((error) =>
16            console.error("micElem.current.play() failed", error)
17          );
18      } else {
19        micRef.current.srcObject = null;
20      }
21    }
22  }, [micStream, micOn]);
23
24  return (
25    <div>
26      <p>
27        Participant: {displayName} | Mic: {micOn ? "ON" : "OFF"}
28      </p>
29      <audio ref={micRef} autoPlay playsInline muted={isLocal} />
30    </div>
31  );
32}
33

Results

You have completed the implementation of a customized audio rooms in React.js using VideoSDK. To explore more features, go through Basic and Advanced features.

Tip: You can checkout the complete quick start example here.

Summarize with

ChatGPTClaudePerplexityGoogleGrok
Prefer VideoSDK on Google

Table of Contents

Start Building Now With $20 Free Balance

No credit card required to start.

Documentation →Github Repo →

Share This Article

TwitterLinkedInFacebookHacker News

Get started for free today

Grab your API keys and start building with free $20 included in your account. Need enterprise-grade security or custom workloads? Talk to an expert!

Book a demo

Video SDK Logo

United States

28 Geary St, Suite 650,
San Francisco, CA 94108, United States

India flag

India

18th Floor, 1812, The Junomoneta Tower,
Adajan-Hazira Rd, Surat, Gujarat 395009, India

Video SDK Logo
Video SDK Logo
Video SDK Logo
Video SDK Logo
SOLUTIONS

Video KYC

Video Banking

Virtual Claim

Video MER

Telehealth

Astrology

Gaming

Dating

Live Commerce

Auto Proctoring

Interview-as-a-service

Virtual Events

Live Audio Streaming

Ed-Tech

PRODUCTS

AI-Agents

Real-time Audio & Video SDK

Interactive Live Streaming SDK

Real-time Transcription SDK

Character SDK

Open Source Examples

SUCCESS STORIES

Examedi

Coderschool

TYHO

ForagerOne

Immigo

DEVELOPERS

Documentation

Code Samples

Developer Updates

Developer Hub

TOP ARTICLES

What is WebRTC?

Build a React Native Video Calling App

Build a Flutter Video Calling App

RESOURCES

The Protocol by Video SDK

AI Apps

Creator Program

LEGAL

Terms Of Service

Privacy Policy

Cookie Notice

CCPA Notice

Subprocessors

DPA

RSS

COMPANY

Contact Us

Pricing

Support

Blog

Press Kit