用声网搭建视频直播推流/视频会议网站可能会有点慢,但如果使用声网 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 中包含了一个高级组件 AgoraUIKit
,AgoraUIKit
组件负责处理实时视频体验的逻辑和 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
在返回语句中,我们用 rtcProps
和 callbacks
对象来渲染 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)
...
首先,我们需要添加两个新的状态变量:isHost
和 isPinned
。我们用 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'}
}
}
...
我们可以用自己的状态来定义 rtcProps
,rtcProps
开关中添加了在主持人和观众之间切换(默认角色是主持人)的角色道具。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
组件,该组件封装了 LocalAudioMute
、LocalVideoMute
和 EndCall
按钮组件。资源库里有一个 RemoteAudioMute
、一个 RemoteVideoMute
和一个 SwapUser
(把用户与 maxUser 交换)按钮。这些组件接收用户对象作为一个道具。
注意:远端控件只能在本地对远程用户的音频和视频进行静音。通话中的其他人不会被静音。
十三、视频视图
我们用 MaxVideoView
和 MinVideoView
这两个组件来渲染用户的视频。这两个组件都用用户对象作为道具。用户数据被划分为两个不同的数组:MaxUser
和 MinUser
。MaxUser
数组通常只包含一个用户,其他用户则在 MinUser
数组中。布局固定的情况下,我们可以用一个数组来渲染大视图,用另一个数组来渲染视频列表,不需要直接与状态进行交互。例如,如果你想替换一个用户,可以使用 SwapUser
按钮,直接从内部改变状态。
如果你不想使用视图搭建自己的布局,可以使用 gridLayout
和 pinnedLayout
组件。
十四、道具背景
PropsContext
使用 React Context API,能访问提供者和消费者组件,然后你可以访问组件树其他地方传递给这个组件的道具。资源库用它来传递组件数上的 rtcProps
、styleProps
和 callbacks
。
十五、用户上下文
我们可以用 MaxUidContext
在 MaxView
(浮动布局中的主视图)中访问包含用户对象的一个数组,用 MinUidContext
在 MinView
(浮动布局的顶部浮动视图)中访问包含用户对象的一个数组,用 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。另外,我们还有 Android、iOS、React Native 和 Flutter 版本的 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