实现音视频互动
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。
首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
- 所有用户调用
joinChannel
方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有的用户角色都为主播。
- 加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole
方法修改用户角色,使其具备发流权限。
前提条件
- Unreal Engine 4.27 及以上版本
- 两台设备,不可使用虚拟机。参考下方列出的 Unreal Engine 官方文档,根据你的目标平台和引擎版本准备开发环境:
开发平台 参考文档 备注 Android Android 开发环境要求 无 iOS iOS 开发环境要求 有效的 Apple 开发者签名。 macOS macOS 开发环境要求 有效的 Apple 开发者签名。 Windows Windows 开发环境要求 32 位 Windows 仅支持 Unreal Engine 4 及以下版本,你需要在 AgoraPluginLibrary.Build.cs
文件中将 Windows 32 相关的代码取消注释。 - 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通服务从声网控制台获得以下信息:
- App ID:声网随机生成的字符串,用于识别你的项目。
- 临时 Token:Token 也称为动态密钥,在客户端加入频道时对用户鉴权。临时 Token 的有效期为 24 小时。
- 频道名:用于标识频道的字符串。
创建项目
参考以下步骤或 Unreal 官方操作指南创建一个 Unreal 项目。如果已有 Unreal 项目,可进行下一步集成 SDK。
- 打开 Unreal Engine,在 New Project Categories 下选择 Games,点击 Next。
- 在 SelectTemplate 页面,选择 Blank,点击 Next。
- 在 Project Settings 页面,进行如下设置:
- 选择 Blueprint 或 C++。
- 根据你开发的目标平台选择 Desktop/Console 或 Mobile/Tablet。
- 选择项目存储路径,并为项目命名。
- 点击 Create Project 完成创建。
集成 SDK
-
前往下载页面,下载最新版本的 Unreal 视频 SDK,并解压缩。
-
在你的项目根目录文件夹下,创建名为
Plugins
的文件夹。 -
将 Unreal SDK 文件夹中的
AgoraPlugin
拷贝到Plugins
中。
创建 UMG
为直观地体验实时音视频互动,需根据应用场景创建以下控件:
- 本地和远端的视频窗口
- 加入和离开频道的按钮
参考以下步骤创建上图所示 UI 界面。如果你的项目中已有用户界面,可进行下一步创建关卡。
- 创建 Widget Blueprint。
- 在 Content Browser 的 Content 文件夹中,右击选择 User Interface > Widget Blueprint 创建 Widget Blueprint,并将其命名为 BP_VideoWidget。
- 双击打开 BP_VideoWidget。此时可以在 Hierarchy 面板中看到 BP_VideoWidget > Canvas Panel。
- 在 Widget Blueprint 中创建本地和远端的视频窗口。
- 创建视图背景。在 Palette 面板中,选择 Common > Image,将其拖至 Canvas Panel 中,命名为 background。通过拖拽调整至画布大小,在 Details 面板中调整背景颜色。
- 创建本地视图窗口。在 Palette 面板中,选择 Common > Image,将其拖至 Canvas Panel 中。将其命名为 Img_LocalVideoView,并在 Details 面板中调整其在画布中的位置和大小:
- Position X:-500
- Position Y:-100
- Size X:640
- Size Y:360
- 重复上述步骤创建远端视图窗口,将其命名为 Img_RemoteVideoView,并调整其在画布中的位置和大小:
- Position X:500
- Position Y:-100
- Size X:640
- Size Y:360
- 在 Widget Blueprint 中创建加入和离开频道的按钮。
- 创建加入频道按钮。选择 Common > Button,将其拖至 Canvas Panel 中,重命名为 Btn_JoinChannel,并调整其在画布中的位置和大小:
- Position X:-500
- Position Y:200
- Size X:100
- Size Y:130
- 选择 Common > Text,将其拖至 Btn_JoinChannel 中,并在 Details 面板中将 Text 文本内容修改为 JoinChannel。
- 重复上述步骤创建离开频道按钮,将其命名为 Btn_LeaveChannel,并将 Text 文本内容修改为 LeaveChannel。调整按钮在画布中的位置和大小:
- Position X:500
- Position Y:200
- Size X:130
- Size Y:130
- 创建加入频道按钮。选择 Common > Button,将其拖至 Canvas Panel 中,重命名为 Btn_JoinChannel,并调整其在画布中的位置和大小:
- 保存上述更改。
实现步骤
本节介绍如何使用声网 RTC SDK 在你的项目中实现实时音视频互动功能。
创建关卡
-
在 Content Browser 的 Content 文件夹中,右击选择 Level 创建 Level Blueprint,并将其命名为 BasicVideoCallScene。
-
双击 BasicVideoCallScene,点击编辑器上方的 Blueprints > Open Level Blueprint 打开关卡蓝图。
实现基础流程
在 My Blueprint 面板中,双击 Graphs > EventGraph 打开事件图表,其中已有 Event BeginPlay (游戏开始) 和 Event End Play (游戏结束) 两个事件节点。接下来,创建实时音视频互动相关的事件节点以及对应的函数和变量,并将它们连接起来以实现实时音视频互动的逻辑和交互,如下图所示:
其中主要节点如下:
序号 | 节点 | 类型 | 描述 |
---|---|---|---|
1 | Set Show Mouse Cursor | 原生* | (可选) 设置是否显示鼠标光标,勾选代表显示。 注意
|
2 | Load Agora Config | 自定义** | 加载声网配置。用于后续在创建和加入频道时验证用户身份。 |
3 | Create BP Video Widget Widget | 原生 | 创建用户界面。步骤如下:
|
4 | Set Basic Video Call Widget | 自定义 | 设置用户界面。步骤如下:
|
5 | Bind UIEvent | 自定义 | 绑定 UI 事件,用于处理点击 JoinChannel 和 LeaveChannel 按钮后的事件逻辑。 |
6 | Add to Viewport | 原生 | 将用户界面添加到视口。 |
7 | Check Permission | 自定义 | (可选) 检查是否已获取实时音视频互动所需的系统权限,如访问摄像头和麦克风等。 注意 如果你的目标平台是 Android,需要创建该节点用于检查系统权限。 |
8 | Init Rtc Engine | 自定义 | 创建并初始化 RTC 引擎。 |
9 | Un Init Rtc Engine | 自定义 | 离开频道并释放资源。 |
*原生节点为蓝图自带的节点,可以直接添加调用。
**自定义节点非蓝图自带,需要在创建自定义函数后才能添加对应节点。
加入频道相关变量
- 创建 Token、ChannelId 和 AppId 三个变量,选择 Variable Type 为 String。
- 在 Load Agora Config 函数中,添加 Sequence 节点,然后分别连接 Set Token、Set Channel Id 和 Set App Id,在其中填入从声网控制台获取的 Token、频道名和 App ID,用于后续创建和加入频道时验证用户身份。
初始化 RTC 引擎
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
-
(可选) 如果你的目标平台是 Android,在初始化 RTC 引擎前,需要检查是否已获取 Android 系统权限。在 CheckPermission 函数中,参照下图创建节点,用于添加 Android 系统中访问麦克风、访问摄像头等权限。
信息如果你的目标平台是 macOS 或 iOS,请参考如何为 Unreal Engine 项目添加实时互动所需的权限?
-
在 InitRtcEngine 函数中,参照下图创建并连接节点以初始化 RTC 引擎。
主要步骤如下:
-
创建
IRtcEngine
和IRtcEngineEventHandler
。- 创建 RtcEngine 和 EventHandler 变量,将 Variable Type 分别设置为 Agora Rtc Engine 和 IRtc Engine Event Handler,即声网 SDK 的基础功能类和事件回调类,用于在蓝图中存储对这两个接口类的引用。
- 添加两个 Construct Object From Class 节点,将 Class 分别设置为 Agora Rtc Engine 和 IRtc Engine Event Handler,并分别连接 Set Rtc Engine 和 Set Event Handler。
-
绑定
IRtcEngineEventHandler
类相关的回调函数。-
创建 onJoinChannelSuccess、onLeaveChannel、onUserJoined 和 onUserOffline 回调函数。参考下表配置回调的输入参数:
回调函数 描述 输入参数 FOnJoinChannelSuccess
成功加入频道回调。 channel
: (String) 频道名。uid
: (Integer64) 加入频道的用户 ID。elapsed
: (Integer) 从本地调用JoinChannel
开始到发生此事件过去的时间(毫秒)。
FOnLeaveChannel
离开频道回调。 stats
: 通话的统计数据。详见FRtcStats
。
FOnUserJoined
远端观众或主播加入当前频道回调。 uid
: (Integer64) 新加入频道的远端观众或主播的用户 ID。elapsed
: (Integer) 从本地调用JoinChannel
开始到发生此事件过去的时间(毫秒)。
FOnUserOffline
远端观众或主播离开当前频道回调。 uid
: (Integer64) 离线观众或主播的用户 ID。reason
: 离线原因。详见EUSER_OFFLINE_REASON_TYPE
。
-
创建 Bind Event 函数,在该函数中,添加 Sequence 节点,然后分别绑定 onJoinChannelSuccess、onLeaveChannel、onUserJoined 和 onUserOffline 回调事件。
-
-
初始化
IRtcEngine
。- 调用 Initialize 初始化 RTC 引擎。
- 连接 RtcEngineContext 配置
IRtcEngine
实例,注意将 Channel Profile 选为 CHANNEL_PROFILE_LIVE_BROADCASTING (直播场景)。
-
绑定 UI 事件
你也可以在 UMG 中绑定 UI 事件,本文仅展示使用 Bind UIEvent 函数进行绑定。
-
创建并实现 OnJoinChannelClicked 事件回调。
主要步骤如下:
- 调用 Enable Video 和 Enable Audio 启用视频和音频模块。
- 调用 Join Channel 加入频道。
- 在 Make ChannelMediaOptions 中设置以下参数:
- 设置 Publish Camera Track 为 AGORA TRUE VALUE,发布摄像头采集的视频流。
- 设置 Publish Microphone Track 为 AGORA TRUE VALUE,发布麦克风采集的音频流。
- 设置 Auto Subscribe Video 为 AGORA TRUE VALUE,自动订阅所有视频流。
- 设置 Auto Subscribe Audio 为 AGORA TRUE VALUE,自动订阅所有音频流。
- 勾选 Client Role Type Set Value 并设置 Client Role Type 为 CLIENT_ROLE_BROADCASTER 或 CLIENT_ROLE_AUDIENCE,设置用户角色为主播或观众。
- 勾选 Channel Profile Set Value 并设置 Channel Profile 为 CHANNEL_PROFILE_LIVE_BROADCASTING,设置频道场景为直播场景。
-
创建并实现 OnLeaveChannelClicked 事件回调。当事件触发时,调用 Leave Channel 离开频道。
-
在 Bind UIEvent 函数中,参考下图将 OnJoinChannelClicked 和 OnLeaveChannelClicked 回调函数分别绑定 JoinChannel 和 LeaveChannel 按钮。点击按钮时,会触发对应的事件回调。
设置本地和远端视图
-
创建并实现 MakeVideoView 函数,在本地或远端的观众或主播加入频道时加载视图。
主要步骤如下:
- 在该函数中,创建 SavedUID、SavedSourceType 和 SavedChannelID 三个本地变量,分别设置 Variable Type 为 Integer64、VIDEO_SOURCE_TYPE 和 String,保存变量在后续加载视图时使用。
- 创建本地视图。本地视图中,uid 为 0,由 SDK 随机分配,视频源类型为 VIDEO_SOURCE_CAMERA_PRIMARY (第一个摄像头)。
- 创建远端视图。远端视图中,uid 为远端发送来的 uid,视频源类型为 VIDEO_SOURCE_REMOTE (网络获取的远端视频)。
-
创建并实现 ReleaseVideoView 函数,在本地或远端的观众或主播离开频道时释放视图。
主要步骤如下:
- 在该函数中,创建 SavedUID、SavedSourceType 和 SavedChannelID 三个本地变量,分别设置 Variable Type 为 Integer64、VIDEO_SOURCE_TYPE 和 String,保存变量在后续释放视图时使用。
- 释放本地视图。
- 释放远端视图。
实现回调函数
将之前创建的 onJoinChannelSuccess、onLeaveChannel、onUserJoined 和 onUserOffline 回调函数按照以下实现步骤进行配置:
-
本地用户成功加入频道后,触发 onJoinChannelSuccess 回调,创建本地视图,uid 为 0,由 SDK 随机分配,视频源类型为 VIDEO_SOURCE_CAMERA_PRIMARY (第一个摄像头)。
-
本地用户离开频道后,触发 onLeaveChannel 回调,释放本地视图。
-
远端用户加入频道时,触发 onUserJoined 回调,创建远端视图,uid 为远端发送来的 uid,视频源类型为 VIDEO_SOURCE_REMOTE (网络获取的远端视频)。
-
远端用户离开频道时,触发 onUserOffline 回调,释放远端视图。
离开频道并释放资源
参考下图实现 UnInitRtcEngine 函数。
主要步骤如下:
- 离开频道。
- 取消注册 RTC 事件回调。
- 销毁
IRtcEngine
对象,释放声网 SDK 使用的所有资源。
后续步骤
- 如果你的目标平台是 macOS 或 iOS,则需要在打包时添加实时互动所需的摄像头和麦克风等权限,详见如何为 Unreal Engine 项目添加实时互动所需的权限?
- 在本文示例中,使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在实时互动直播的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY
)实现。详见实现极速直播。
测试你的项目
按照以下步骤来测试你的实时音视频互动项目:
- 在 Load Agora Config 函数中,分别填入将你的项目的 App ID、频道名以及临时 Token。
- 在 Unreal Editor 中,点击 来运行你的项目,然后点击 JoinChannel 加入频道。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。如果你的朋友以主播身份加入,你们可以听见、看见对方;如果作为观众加入,你只能看到自己,你的朋友可以看到你并听到你的声音。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
- 为什么 SDK 中使用的是动态库而不是静态库?