声网 Web UIKit:只需 5 行代码就能给网站添加视频聊天/直播推流功能

用声网搭建视频直播推流/视频会议网站可能会有点慢,但如果使用声网 Web UIKit,只需五行代码就能轻松给网站添加视频通话功能!而且声网 Web UIKit 功能齐全,支持扩展和自定义,是不是跃跃欲试呢?


一、功能特色

  • 支持视频会议和直播推流
  • 即插即用,没有水印和商标
  • 具有适用于电脑桌面和移动设备的响应式布局
  • 使用 React 自定义 UI 和功能
  • 自动管理令牌(用双击服务器部署)
  • 双流模式和说话人自动识别
  • 由可重组的模块化功能组件搭建
  • 支持 TypeScript,没有第三方依赖
  • 可作为 Web 组件使用
  • 每月有 10,000 分钟的免费使用时间

声网 Web UIKit 必须在 React 框架中使用。如果你的网站用的是 JavaScript 或其他框架(如:Svelte、Vue 或 Angular),可以把 UIKit 当做 web 组件使用(请直接跳到本文最后一部分开始阅读)。


二、前期准备


三、设置

首先,在 GitHub 上找到这个示例的代码,然后使用 Typescript 创建一个 React 项目,打开一个终端并执行:

npx create-react-app demo --template typescript
cd demo


大家也可以用自己的项目,从 NPM 里安装声网 Web UIKit:

npm i agora-react-uikit

注意:截止2022年1月27日, agora-react-uikit 的最新版本是 v0.0.5 agora-rtc-sdk-ng 的最新版本是 is v4.8.1

设置完成后,运行 npm start 来启动 React 服务器,并访问 localhost:3000 上的 hello world 应用。


四、添加视频推流功能

声网 Web UIKit 中包含了一个高级组件 AgoraUIKitAgoraUIKit 组件负责处理实时视频体验的逻辑和 UI,我们向这个组件传递道具来进行行为和功能的自定义。首先,我们清除 App.tsx 文件,然后编写代码,搭建一个视频聊天应用:

import React, { useState } from 'react'
import AgoraUIKit, { PropsInterface } from 'agora-react-uikit'

const App: React.FunctionComponent = () => {
  const [videocall, setVideocall] = useState(true)
  const props: PropsInterface = {
    rtcProps: {
      appId: '<Your Agora App ID>',
      channel: 'test',
      token: null, // pass in channel token if the app is in secure mode
    },
    callbacks: {
      EndCall: () => setVideocall(false)
    }
  }
...


然后,我们从 agora-react-uikit 包中导入 AgoraUIKit 组件。App 组件内有一个状态变量 videoCall ,当该变量为“true”时,我们对 UIKit 组件进行渲染;当该变量为“false”时,UIKit 组件会被卸载。我们在 rtcProps 对象中定义声网 App ID、频道名和用户角色,同一频道的用户可以互相交流。频道名可以由任何字母数字字符串组成。

注意:如果你的应用处于安全模式,可以从声网控制台生成一个令牌来进行测试。我们稍后会仔细讨论令牌的使用方法。

callbacks 对象中的 RTC 事件是密钥,回调函数是值——我们使用 EndCall 事件来更新状态并卸载 AgoraUIKit 组件。

...
  return (
    <div style={styles.container}>
      {videocall ? (
        <AgoraUIKit
          rtcProps={props.rtcProps}
          callbacks={props.callbacks} />
      ) : (
        null
      )}
    </div>
  )
}

const styles = {
  container: { width: '100vw', height: '100vh', display: 'flex', flex: 1},
}

export default App


在返回语句中,我们用 rtcPropscallbacks 对象来渲染 AgoraUIKit 组件(卸载声网Agora UIKit 组件后会自动执行清理工作)。

UIKit 组件还兼容 styleProps 道具,这个道具可以编写 React 样式从而自定义应用的外观。我们可以用自定义的样式覆盖 UIKit 的默认样式(如按钮、视频和容器)。


五、直播推流

现在,我们要把一个视频会议网站转变成一个直播推流应用,用户可以以主持人或观众的角色加入,主持人可以向频道中的所有用户分享音视频,而观众只能从主持人那里接收音视频。

...
import AgoraUIKit, { PropsInterface, layout } from 'agora-react-uikit'

const App: React.FunctionComponent = () => {
  const [videocall, setVideocall] = useState(true)
  const [isHost, setHost] = useState(false)
  const [isPinned, setPinned] = useState(false)
...


首先,我们需要添加两个新的状态变量:isHostisPinned 。我们用 isHost 变量追踪用户的角色,确定用户是主持人还是观众,用 isPinned 变量在两个预建的布局之间进行切换:

...
  const props: PropsInterface = {
    rtcProps: {
      appId: '<Your Agora App ID>',
      channel: 'test',
      role: isHost ? 'host' : 'audience',
      layout: isPinned ? layout.pin : layout.grid,
    },
    callbacks: {
      EndCall: () => setVideocall(false)
    },
    styleProps: {
      localBtnContainer: {backgroundColor: 'blueviolet'}
    }
  }
...


我们可以用自己的状态来定义 rtcPropsrtcProps 开关中添加了在主持人和观众之间切换(默认角色是主持人)的角色道具。UIKit 道具是动态的,如果我们更新了状态,该状态作为道具传递,UIKit 会随之变化(与标准的 React 设计模式类似)。我们正在使用 styleProps 改变底栏的背景颜色:

...
return (
    <div style={styles.container}>
        {videocall ? (<>
          <div style={styles.nav}>
            <p style={{ fontSize: 20, width: 200 }}>You're {isHost ? 'a host' : 'an audience'}</p>
            <p style={styles.btn} onClick={() => setRole(!isHost)}>Change Role</p>
            <p style={styles.btn} onClick={() => setPinned(!isPinned)}>Change Layout</p>
          </div>
          <AgoraUIKit
            rtcProps={props.rtcProps}
            callbacks={props.callbacks}
            styleProps={props.styleProps} /></>
        ) : (
          <h3 style={styles.btn} onClick={() => setVideocall(true)}>Start Call</h3>
        )}
      </div>
    </div>
  )
}
...


接下来,我们会更新 UI,添加切换状态的按钮,把 styleProps 添加到 UIKit 中。 如果视频呼叫状态为 false,不要返回 null,添加一个 h3 标签,通过更新状态在上一次呼叫结束后立即再次呼叫。

这里有很多可供参考的样式:

...
const styles = {
  container: { width: '100vw', height: '100vh', display: 'flex', flex: 1, backgroundColor: '#007bff22'},
  heading: { textAlign: 'center' as const, marginBottom: 0 },
  videoContainer: { display: 'flex', flexDirection: 'column', flex: 1 } as React.CSSProperties,
  nav: { display: 'flex', justifyContent: 'space-around' },
  btn: { backgroundColor: '#007bff', cursor: 'pointer', borderRadius: 5, padding: 5, color: '#ffffff', fontSize: 20 },
}

export default App


六、用 RtcProps 自定义功能

我们可以用 RtcProps 对象自定义 UIKit 的工作方式,还可以选择功能和布局,现在 RtcProps 自定义的使用范围越来越广。


七、令牌管理

如果大家使用声网 Web UIKit 搭建生产级应用,我们强烈建议使用令牌来保护应用。有两种使用令牌的方法:如果大家已经设置了令牌服务器,可以通过令牌属性手动给 UIKit 提供一个令牌。

如果没有令牌服务器,可以使用 tokenUrl 属性,该属性可以自动为频道获取一个新的访问令牌,而且会在令牌快要过期时自动更新。请求新令牌的功能需要令牌符合 GitHub上预建的 Golang 令牌服务器中的 URL 方案:AgoraIO-Community/agora-token-service. 你可以使用这个链接双击鼠标把它部署到 Heorku 上。


八、在非 React 框架中使用 Web UIKit

声网 Web UIKit 也可作为 Web 组件,用于用原生 JavaScript 或 Angular、Vue 和 Avelte 等框架搭建的网站。要在这样的网站上添加视频通话功能,只需将声网 Web UIKit 作为脚本导入,然后,通过传递声网 App ID 和频道名在 DOM 中使用声网 Web UIKit。

...
  <body>
    <script src="agora-uikit.js"></script>
    <agora-react-web-uikit
      style="width: 100%; height: 100vh; display: flex;"
      appId=''
      channel='test'
    />
    <script>
      // select web component
      const el = document.querySelector('agora-react-web-uikit');
      
      // alternatively you can do this to pass props
      // el.appId = '<Your App ID>'
      
      // Add event listener and subscribe to custom event
      el.addEventListener('agoraUIKitEndcall', (e) => {
        console.log('hello from html')
        // handle endcall event
        el.remove();
      });
    </script>
...


我们可以在 JS 中访问 Web 组件元素并更新对象属性,这样可以用编程的方式更新道具,比如,这样做更有利于在直播推流应用中搭建更新用户角色的按钮。我们可以为结束通话按钮添加事件监听器,如果用户点击结束通话按钮,事件监听器就会处理所有工作。我们非常期待大家的反馈,希望大家可以打开功能请求,这样我们就可以给 Web 组件版本添加更多的 RTC 事件。

虽然目前 Web 组件还有局限性,但本文中提到的都可以实现。我们会根据大家的反馈,在 react 版本之外,持续给这个版本的 UIKit 添加功能和支持。


九、高级:重组 UIKit

如果你需要更精细的控件,或者想为应用搭建一个自定义布局,但 AgoraUIKit 组件不支持,你可以提取和使用组成 UIKit 的单个组件进行重组,建立自己的自定义解决方案,并且不用管理 SDK。

UIKit 并不局限于使用 AgoraUIKit 组件,它是一个由几个模块化组件组成的高级组件,所以用起来非常方便。你可以导入并使用单个部件来组成你的应用。


十、RtcConfigure

RtcConfigure 组件包含视频通话的所有逻辑,它处理所有的 SDK 事件并维护应用的状态。你可以在 RtcConfigure 组件内封装其他 UIKit 组件以获得对用户对象的访问。

它还设置了 RtcContext 用来访问 Web SDK 客户端对象以及包含远端音轨和本地音轨的 mediaStore (以及用于改变状态的调度函数)。


十一、TracksConfigure

TrackConfigure 组件负责为应用创建音频和视频轨道。


十二、控件

UIKit输出了一个 LocalControls 组件,该组件封装了 LocalAudioMuteLocalVideoMuteEndCall 按钮组件。资源库里有一个 RemoteAudioMute 、一个 RemoteVideoMute 和一个 SwapUser (把用户与 maxUser 交换)按钮。这些组件接收用户对象作为一个道具。


注意:远端控件只能在本地对远程用户的音频和视频进行静音。通话中的其他人不会被静音。


十三、视频视图

我们用 MaxVideoViewMinVideoView 这两个组件来渲染用户的视频。这两个组件都用用户对象作为道具。用户数据被划分为两个不同的数组:MaxUserMinUserMaxUser 数组通常只包含一个用户,其他用户则在 MinUser 数组中。布局固定的情况下,我们可以用一个数组来渲染大视图,用另一个数组来渲染视频列表,不需要直接与状态进行交互。例如,如果你想替换一个用户,可以使用 SwapUser 按钮,直接从内部改变状态。

如果你不想使用视图搭建自己的布局,可以使用 gridLayoutpinnedLayout 组件。


十四、道具背景

PropsContext 使用 React Context API,能访问提供者和消费者组件,然后你可以访问组件树其他地方传递给这个组件的道具。资源库用它来传递组件数上的 rtcPropsstylePropscallbacks


十五、用户上下文

我们可以用 MaxUidContextMaxView (浮动布局中的主视图)中访问包含用户对象的一个数组,用 MinUidContextMinView (浮动布局的顶部浮动视图)中访问包含用户对象的一个数组,用 LocalUserContext 访问本地用户的状态。


十六、重组示例

我们通过搭建高级组件来查看这些组件的作用,下面的示例省略了一些细节(如定义道具和样式),如果你需要更多信息,可以查看 AgoraUIKit 组件。

import React, { useContext } from 'react'
import RtcConfigure from './RTCConfigure'
import PropsContext, { PropsProvider, PropsInterface } from './PropsContext'
import LocalControls from './Controls/LocalControls'
import TracksConfigure from './TracksConfigure'
import { MaxUidContext, MaxVideoView, MinUidContext } from './'
import RtcContext from './RtcContext'

const AgoraUIKit: React.FC<PropsInterface> = () => {
  const rtcProps = {
    // define your props
  }

  return (
    <PropsProvider value={rtcProps}>
      {rtcProps.role === 'audience' ? (
        <VideocallUI />
      ) : (
        <TracksConfigure>
          <VideocallUI />
        </TracksConfigure>
      )}
    </PropsProvider>
  )
}

const VideocallUI = () => {
  const { rtcProps } = useContext(PropsContext)

  return (
    <RtcConfigure callActive={rtcProps.callActive}>
      <RenderVideos />
      <LocalControls />
    </RtcConfigure>
  )
}

const RenderVideos = () => {
  const max = useContext(MaxUidContext)
  const min = useContext(MinUidContext)
  const users = [...max, ...min]

  // you can access the Web SDK client and tracks here
  const { client, localVideoTrack } = useContext(RtcContext)
  console.log(client.getRTCStats())
  console.log(localVideoTrack?.getCurrentFrameData())

  return (
    <div>
      {users.map((user) => (
        <MaxVideoView user={user} key={user.uid} />
      ))}
    </div>
  )
}

export default AgoraUIKit


我们将应用包裹在 <PropsProvider> 中,让其他组件可以访问道具。如果用户是主持人,我们将 <VideoCallUI> 封装在 <TracksConfigure> 组件中,该组件创建并传递麦克风和摄像头轨道。

<VideoCallUI> 封装在 <RtcConfigure> 中,<RtcConfigure> 中包含了视频通话/直播推流的所有逻辑,也设置了本地或远端用户的状态。我们用 <LocalControls> 来渲染控件底栏,旁边的 <RenderVideos> 组件访问用户上下文,并使用 <MaxVideoView> 组件对每个用户进行映射从而渲染视频。


总结

我们期待能收到大家的反馈,如果大家有任何功能请求,请打开拉动请求。我们也欢迎大家在 GitHub 问题中报告 bug。另外,我们还有 AndroidiOSReact NativeFlutter 版本的 UIKit,欢迎查看哦~

如果你在使用 Web UIKit 时遇到问题,可以在 GitHub Repo 上提出功能请求或报告bug。


原文作者:Ekaansh Arora
原文链接:Adding Video Chat or Live Streaming to Your Website in 5 lines of Code Using the Agora Web UIKit
推荐阅读
相关专栏
SDK 教程
164 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。