编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

构建可扩展且高性能的React与VideoSDK的直播应用程序

wxchong 2024-07-06 01:03:33 开源技术 14 ℃ 0 评论

学习如何通过逐步教程创建强大的直播流应用程序。探索React和视频SDK的无缝集成,构建交互式直播流体验。跟随我们的指导,从设置环境到实现实时聊天、直播视频流和交互式参与工具等关键功能的开发过程。释放React和视频SDK的潜力,创建一个吸引观众的迷人直播流应用程序。立即开始,将您的直播流应用程序开发技能提升到新的水平!

在当今数字时代,直播流已成为分享内容和实时吸引观众的日益流行媒介。随着YouTube、Twitch和Facebook Live等平台的兴起,企业和个人都在探索利用直播视频的力量与目标观众建立联系。如果您希望使用React和视频SDK构建交互式直播流应用程序,那么您来对地方了。在本文中,我们将指导您创建一款尖端的直播流应用程序,帮助您在竞争中脱颖而出。

React已成为最广泛使用的JavaScript框架之一,用于构建用户界面。其基于组件的架构、虚拟DOM和高效渲染使其成为开发人员的热门选择。当与视频SDK结合使用时,视频SDK是一个强大的工具包,为开发人员提供了集成实时视频流到其应用程序所需的工具和功能,React在直播流领域变得更加强大。

用于构建交互式直播流应用程序的工具

  • VideoSDK.Live的React SDK
  • VideoSDK.Live的HLS组合
  • VideoSDK.Live的HLS流

使用视频SDK构建React交互式直播流应用程序的四个步骤

步骤1:了解您的直播流应用程序功能和项目结构

我将为两种类型的用户创建此应用程序,即“演讲者”和“观众”。

  • 演讲者将拥有所有媒体控件,即他们可以切换他们的网络摄像头和麦克风,与观众分享信息。演讲者还可以启动HLS流,以便观众消费内容。
  • 观众将没有任何媒体控件,他们只能观看由演讲者启动的VideoSDK HLS流。

开始编写代码之前的先决条件:

  • VideoSDK账户。如果没有,请注册
  • 用于React的编码环境
  • 对React的良好理解

在设置好编码环境后,我们现在可以开始编写我们的代码,首先我将使用create-react-app创建一个新的React应用程序,同时安装一些有用的依赖项。

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

项目结构

我将创建三个屏幕:

  1. 欢迎屏幕
  2. 演讲者屏幕
  3. 观众屏幕

以下是我们应用程序的文件夹结构。

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.js,这个文件将包含所有屏幕,并根据appData状态的变化有条件地渲染它们。

/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;

步骤2:您的React直播流应用程序的欢迎屏幕

创建一个新的会议将需要一个API调用,因此我们将为此编写一些代码。

在生产中,可以从用户仪表板获取临时的授权令牌,但我们建议使用您的服务器生成的授权令牌。

遵循此指南从用户仪表板获取临时授权令牌。

/src/api.js

export const authToken = "temporary-generated-auth-token-goes-here";
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将用于由演讲者创建新会议。它还将允许输入已创建的meetingId以加入现有会话。

src/screens/WelcomeScreenContainer.js

import React, { useState } from "react";
import { createNewRoom } from "../api";
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;

步骤3:演讲者屏幕

这个屏幕将包含所有的媒体控件和参与者网格。首先,我将为即将加入的参与者创建一个名称输入框。

src/screens/speakerScreen/SpeakerScreenContainer.js

import { MeetingProvider } from "@videosdk.live/react-sdk";
import React from "react";
import MediaControlsContainer from "./MediaControlsContainer";
import ParticipantsGridContainer from "./ParticipantsGridContainer";
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

这个容器将用于切换麦克风和网络摄像头。此外,我们将添加一些代码来启动HLS流。

import { useMeeting, Constants } from "@videosdk.live/react-sdk";
import React, { useMemo } from "react";
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

这将从useMeeting钩子获取所有已加入的参与者,并将它们单独渲染。在这里,我们将使用SingleParticipantContainer来渲染单个参与者的网络摄像头流。

src/screens/speakerScreen/ParticipantsGridContainer.js

import { useMeeting } from "@videosdk.live/react-sdk";
import React, { useMemo } from "react";
import SingleParticipantContainer from "./SingleParticipantContainer";
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

这个容器将从props获取participantId,并从useParticipant钩子获取网络摄像头流和其他信息。它将渲染提供的参与者ID的音频和视频流。

src/screens/speakerScreen/SingleParticipantContainer.js

import { useParticipant } from "@videosdk.live/react-sdk";
import React, { useEffect, useMemo, useRef } from "react";
import ReactPlayer from "react-player";
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;

我们的演讲者屏幕已经完成,现在我们可以开始编写ViewerScreenContainer

步骤 4:观众屏幕

观众屏幕将用于观众参与者,当演讲者开始直播时,他们将观看HLS流。\ 与演讲者屏幕一样,这个屏幕也将有初始化过程。\ src/screens/ViewerScreenContainer.js

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";
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;

我们的观众屏幕已经完成,现在我们可以测试我们的应用。\ npm run start

交互式直播应用的输出

此应用的源代码可在此GithubRepo中找到。

接下来做什么?

这只是使用Video SDK构建交互式直播应用的一个非常基本的示例,您可以按照自己的方式进行自定义。

  • 添加更多的CSS使UI更具交互性
  • 使用PubSub添加聊天功能
  • 实现Change Mode,通过这个功能,我们可以将任何参与者从观众切换到演讲者,反之亦然。
  • 您还可以参考我们使用VideoSDK的React包构建的预构建应用。这是Github Repo。

更多React资源

  • React视频通话快速入门文档
  • React交互式直播快速入门文档
  • 使用React Hooks构建视频聊天应用
  • 代码示例

结论

通过这样,我们成功地使用Video SDK构建了React交互式直播应用。如果您想要添加聊天消息和屏幕共享等功能,您可以随时参考文档。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表