实现音视频互动
- Windows
更新时间不可用
了解如何快速接入实时互动 RTC,完成环境准备、参数配置、示例运行和核心流程验证。
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- Android Studio 4.1 以上版本。
- Android API 级别 16 或以上。
- 两台运行 Android 4.1 或以上版本的移动设备。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
本小节介绍如何创建项目并为项目添加体验实时互动所需的权限。
-
(可选) 创建新项目。详见 Create a project。
-
打开 Android Studio,选择 New Project。
-
选择 Phone and Tablet > Empty Views Activity,点击 Next。
-
设置项目名称和存储路径,选择语言为 Java,点击 Finish 创建 Android 项目。
注意
创建项目后,Android Studio 会自动开始同步 Gradle,稍等片刻至同步成功后再进行下一步操作。
-
-
添加网络及设备权限。
打开
/app/src/main/AndroidManifest.xml文件,在</application>后面添加如下权限:XML <!--必要权限--> <uses-permission android:name="android.permission.INTERNET"/> <!--可选权限--> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- 对于 Android 12.0 及以上且集成 v4.1.0 以下 SDK 的设备,还需要添加以下权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <!-- 对于 Android 12.0 及以上设备,还需要添加以下权限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> -
防止代码混淆。
如果你的 App 未开启 R8/ProGuard 缩减和混淆,无需额外配置混淆规则。如果你的 App 开启了 R8/ProGuard 缩减和混淆,请根据集成方式选择以下任一配置:
-
快速配置:打开
/app/proguard-rules.pro文件,添加如下规则,保留所有声网 SDK 相关类:Java -keep class io.agora.**{*;} -dontwarn io.agora.** -
精细化配置:如果你对 App 包体积、代码缩减或混淆效果有更高要求,可以使用 SDK 提供的
consumer-proguard-rules.pro文件。该文件仅保留 Native 层通过 JNI 访问所需的 Java 类、成员和方法,使其他 SDK Java 代码可继续参与 R8/ProGuard 的缩减、优化和混淆。通过 AAR 集成时,
consumer-proguard-rules.pro已包含在 AAR 中,打包时会自动生效,无需手动拷贝。通过 JAR 集成时,你需要将consumer-proguard-rules.pro手动拷贝到工程中,并在build.gradle中添加该文件,例如:Text android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'consumer-proguard-rules.pro' } } }
-
集成 SDK
你可以选用以下任一方式集成声网实时互动 SDK。
-
进入项目根目录,打开
settings.gradle文件,在dependencyResolutionManagement的repositories中添加声网 Maven CDN 仓库。请保留项目中已有的 Maven 仓库配置,尤其是
mavenCentral(),并额外添加声网 Maven CDN 仓库。注意
如果你在
settings.gradle中找不到dependencyResolutionManagement字段,可能是因为你的 Android Gradle Plugin 版本低于 v7.1.0。groovy dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() maven { url = 'https://download.shengwang.cn/maven/' } } }若你的 Android Gradle Plugin 版本低于 v7.1.0,请打开项目根目录下的
build.gradle文件,在allprojects的repositories中添加如下配置:groovy allprojects { repositories { mavenCentral() maven { url = 'https://download.shengwang.cn/maven/' } } } -
打开
/app/build.gradle文件,在dependencies中添加声网 RTC SDK 的依赖。你可以从发版说明中查询 SDK 的最新版本,并将x.y.z替换为具体的版本号。groovy ... dependencies { ... // 对于 4.6.0 及之后的版本 // x.y.z 替换为具体的 SDK 版本号,如:4.6.1 // 集成 Full SDK implementation 'cn.shengwang.rtc:full-sdk:x.y.z' // 集成 Lite SDK implementation 'cn.shengwang.rtc:lite-sdk:x.y.z' // 对于 4.6.0 之前的版本 // x.y.z 替换为具体的 SDK 版本号,如:4.0.0 或 4.1.0-1 // 集成 Full SDK implementation 'io.agora.rtc:full-sdk:x.y.z' // 或集成 Lite SDK implementation 'io.agora.rtc:lite-sdk:x.y.z' }注意
Lite SDK 默认无法与 RTC 小程序 SDK 互通。如果需要,请联系技术支持。
-
在下载页面下载最新版本的 Android 实时互动 SDK,并解压。
-
打开解压文件,将以下文件或子文件夹复制到你的项目路径中。
表格内容超出当前宽度,可横向滚动查看更多列。文件或子文件夹 项目路径 agora-rtc-sdk.jar文件/app/libs/arm64-v8a文件夹/app/src/main/jniLibs/armeabi-v7a文件夹/app/src/main/jniLibs/x86文件夹/app/src/main/jniLibs/x86_64文件夹/app/src/main/jniLibs/high_level_api中的include文件夹/app/src/main/jniLibs/注意
自 4.5.0 起,RTC SDK 和 RTM SDK (2.2.0 及以上版本) 都包含
libaosl.so库。如果你通过 CDN 手动集成 RTC SDK 且同时集成了 RTM SDK,为避免冲突,请手动删除版本较低的libaosl.so库。4.6.0 RTC SDKlibaosl.so库版本为 1.3.0。 -
在 Android Studio 的左侧导航栏上选择
Project Files/app/libs/agora-rtc-sdk.jar文件,右键单击,在下拉菜单中选择add as a library。
创建用户界面
根据实时音视频互动的场景需要,为你的项目创建两个视图框,分别用于展示本地视频和远端视频。如下图所示:
复制以下代码到 /app/src/main/res/layout/activity_main.xml 文件中替换原有内容,即可快速创建场景所需的用户界面。
实现步骤
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程:
下面列出了一段实现实时互动基本流程的完整代码以供参考。复制以下代码到 /app/src/main/java/com/example/<projectname>/MainActivity.java 文件中替换 package com.example.<projectname> 后的全部内容,即可快速体验实时互动基础功能。
信息
在 appId、token 和 channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
处理权限请求
本小节介绍如何导入 Android 相关的类并获取 Android 设备的摄像头、录音等权限。
-
导入 Android 相关的类
Java import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.view.SurfaceView; import android.widget.FrameLayout; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; -
获取 Android 权限
启动应用程序时,检查是否已在 App 中授予了实现实时互动所需的权限。
Java private static final int PERMISSION_REQ_ID = 22; // 获取体验实时音视频互动所需的录音、摄像头等权限 private String[] getRequiredPermissions(){ // 判断 targetSDKVersion 31 及以上时所需的权限 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { return new String[]{ Manifest.permission.RECORD_AUDIO, // 录音权限 Manifest.permission.CAMERA, // 摄像头权限 Manifest.permission.READ_PHONE_STATE, // 读取电话状态权限 Manifest.permission.BLUETOOTH_CONNECT // 蓝牙连接权限 }; } else { return new String[]{ Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA }; } } private boolean checkPermissions() { for (String permission : getRequiredPermissions()) { int permissionCheck = ContextCompat.checkSelfPermission(this, permission); if (permissionCheck != PackageManager.PERMISSION_GRANTED) { return false; } } return true; }
导入声网相关的类
导入声网 RTC SDK 相关的类和接口:
import io.agora.rtc2.ChannelMediaOptions;
import io.agora.rtc2.Constants;
import io.agora.rtc2.IRtcEngineEventHandler;
import io.agora.rtc2.RtcEngine;
import io.agora.rtc2.RtcEngineConfig;
import io.agora.rtc2.video.VideoCanvas;定义 App ID 和 Token
传入从声网控制台获取的 App ID、临时 Token,以及生成临时 Token 时填入的频道名,用于后续初始化引擎和加入频道。
// 填写声网控制台中获取的 App ID
private String appId = "<#Your App ID#>";
// 填写频道名
private String channelName = "<#Your channel name#>";
// 填写声网控制台中生成的临时 Token
private String token = "<#Your Token#>";初始化引擎
调用 create [2/2] 方法初始化 RtcEngine。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
private RtcEngine mRtcEngine;
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
...
};
// 创建 RtcEngineConfig 对象,并进行配置
RtcEngineConfig config = new RtcEngineConfig();
config.mContext = getBaseContext();
config.mAppId = appId;
config.mEventHandler = mRtcEventHandler;
// 创建并初始化 RtcEngine
mRtcEngine = RtcEngine.create(config);启用视频模块
按照以下步骤启用视频模块:
- 调用
enableVideo方法,启用视频模块。 - 调用
setupLocalVideo方法初始化本地视图,同时设置本地的视频显示属性。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
mRtcEngine.enableVideo();
// 创建一个 SurfaceView 对象,并将其作为 FrameLayout 的子对象
FrameLayout container = findViewById(R.id.local_video_view_container);
SurfaceView surfaceView = new SurfaceView (getBaseContext());
container.addView(surfaceView);
// 将 SurfaceView 对象传入声网实时互动 SDK,设置本地视图
mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
// 开启本地预览
mRtcEngine.startPreview();加入频道并发布音视频流
调用 joinChannel [2/2] 加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置频道场景为
BROADCASTING(直播场景) 并设置用户角色设置为BROADCASTER(主播) 或AUDIENCE(观众)。 - 将
publishMicrophoneTrack和publishCameraTrack设置为true,发布麦克风采集的音频和摄像头采集的视频。 - 将
autoSubscribeAudio和autoSubscribeVideo设置为true,自动订阅所有音视频流。
// 创建 ChannelMediaOptions 对象,并进行配置
ChannelMediaOptions options = new ChannelMediaOptions();
// 设置用户角色为 BROADCASTER (主播) 或 AUDIENCE (观众)
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
// 设置频道场景为 BROADCASTING (直播场景)
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true;
// 发布摄像头采集的视频
options.publishCameraTrack = true;
// 自动订阅所有音频流
options.autoSubscribeAudio = true;
// 自动订阅所有视频流
options.autoSubscribeVideo = true;
// 使用临时 Token 和频道名加入频道,uid 为 0 表示引擎内部随机生成用户名
// 成功后会触发 onJoinChannelSuccess 回调
mRtcEngine.joinChannel(token, channelName, 0, options);设置远端视图
调用 setupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 onUserJoined 回调获取远端用户的 uid。
private void setupRemoteVideo(int uid) {
FrameLayout container = findViewById(R.id.remote_video_view_container);
SurfaceView surfaceView = new SurfaceView (getBaseContext());
surfaceView.setZOrderMediaOverlay(true);
container.addView(surfaceView);
// 将 SurfaceView 对象传入声网实时互动 SDK,设置远端视图
mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid));
}实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示如何实现 onJoinChannelSuccess、 onUserJoined 和 onUserOffline 回调。
// 成功加入频道回调
@Override
public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
super.onJoinChannelSuccess(channel, uid, elapsed);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "Join channel success", Toast.LENGTH_SHORT).show();
});
}
// 远端用户或主播加入当前频道回调
@Override
public void onUserJoined(int uid, int elapsed) {
runOnUiThread(() -> {
// 当远端用户加入频道后,显示指定 uid 的远端视频流
setupRemoteVideo(uid);
});
}
// 远端用户或主播离开当前频道回调
@Override
public void onUserOffline(int uid, int reason) {
super.onUserOffline(uid, reason);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "User offline: " + uid, Toast.LENGTH_SHORT).show();
});
}开始音视频互动
在 onCreate 中调用一系列方法加载界面布局、检查 App 是否获取实时互动所需权限,并加入频道开始音视频互动。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 如果已经授权,则初始化 RtcEngine 并加入频道
if (checkPermissions()) {
initializeAndJoinChannel();
} else {
ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSION_REQ_ID);
}
}结束音视频互动
按照以下步骤结束音视频互动:
-
调用
stopPreview停止视频预览。 -
调用
leaveChannel离开当前频道,释放所有会话相关的资源。 -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。注意
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
destroy后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
- 调用
Java @Override protected void onDestroy() { super.onDestroy(); if (mRtcEngine != null) { // 停止本地视频预览 mRtcEngine.stopPreview(); // 离开频道 mRtcEngine.leaveChannel(); mRtcEngine = null; // 销毁引擎 RtcEngine.destroy(); } } - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
调试 App
按照以下步骤测试直播 App:
-
开启 Android 设备的开发者选项,打开 USB 调试,通过 USB 连接线将 Android 设备接入电脑,并在 Android 设备选项中勾选你的 Android 设备。
-
在 Android Studio 中,点击
(Sync Project with Gradle Files) 进行 Gradle 同步。
-
待同步成功后,点击
(Run 'app') 开始编译。片刻后,App 便会安装到你的 Android 设备上。
-
启动 App,授予录音和摄像头权限,如果你将用户角色设置为主播,便会在本地视图中看到自己。
-
使用第二台 Android 设备,重复以上步骤,在该设备上安装 App、打开 App 加入频道,观察测试结果:
- 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
- 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。
后续步骤
在完成音视频互动后,你可以阅读以下文档进一步了解:
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为保证通信安全,声网推荐从服务器中获取 Token,详情请参考使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在实时音视频互动的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY) 实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- Xcode 12.0 或以上版本。
- Apple 开发者账号。
- 如需使用 Cocoapods 集成 SDK,则确保已安装 Cocoapods,否则请参考 Getting Started with CocoaPods 进行安装。
- 两台 iOS 9.0 或以上版本的设备。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
按照以下步骤,在 Xcode 中创建一个项目:
-
参考 Create a project 创建一个新的项目。Application 选择 App,Interface 选择 Storyboard,Language 选择 Swift。
信息
如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登入 Apple ID,点击 Next,完成后即可选择你的 Apple 账户作为开发团队。
-
为你的项目设置自动签名。
-
设置部署你的 App 的目标设备。
-
添加项目的设备权限。
在项目导航栏中打开
info.plist文件,编辑属性列表,添加实时互动所需的录音和摄像头权限。信息
- 下表中列出的权限均为可选权限。但如果不添加所列权限,你将无法使用麦克风和摄像头进行实时音视频互动。
- 如果你的项目中需要添加第三方插件或库(例如第三方摄像头),且该插件或库的签名与项目的签名不一致,你还需勾选 Hardened Runtime > Runtime Exceptions 中的 Disable Library Validation。
- 更多注意事项,可以参考 Preparing Your App for Distribution。
表格内容超出当前宽度,可横向滚动查看更多列。Key Type Value Privacy - Microphone Usage Description String 使用麦克风的目的,例如:for a call or live interactive streaming。 Privacy - Camera Usage Description String 使用摄像头的目的,例如:for a call or live interactive streaming。 - 下表中列出的权限均为可选权限。但如果不添加所列权限,你将无法使用麦克风和摄像头进行实时音视频互动。
集成 SDK
根据实际情况,在以下集成方式中任选一种,在你的项目中集成 SDK。
-
在终端里进入项目根目录,并运行
pod init命令。项目文件夹下会生成一个Podfile文本文件。 -
打开
Podfile文件,修改文件为如下内容。注意将Your App替换为你的 Target 名称。Ruby platform :ios, '9.0' target 'Your App' do # 对于 4.6.0 及之后的版本 # x.y.z 请填写具体的 SDK 版本号,如 4.6.0。可通过发版说明获取最新版本号 # 集成 Full SDK pod 'ShengwangRtcEngine_iOS', 'x.y.z' # 集成 Lite SDK pod 'ShengwangLite_iOS', 'x.y.z', # 对于 4.6.0 之前的版本 # x.y.z 请填写具体的 SDK 版本号,如 4.0.1。可通过发版说明获取最新版本号 # 集成 Full SDK pod 'AgoraRtcEngine_iOS', 'x.y.z' # 或集成 Lite SDK pod 'AgoraLite_iOS', 'x.y.z' end注意
Lite SDK 默认无法与 RTC 小程序 SDK 互通。如果需要,请联系技术支持。
-
在终端内运行
pod install命令安装声网 SDK。成功安装后,Terminal 中会显示Pod installation complete!。 -
成功安装后,项目文件夹下会生成一个后缀为
.xcworkspace的文件,通过 Xcode 打开该文件进行后续操作。
-
前往下载页面,获取最新版的 SDK,然后解压。
-
将 SDK 包内
libs路径下的文件,拷贝到你的项目路径下。 -
打开 Xcode,添加对应动态库,确保添加的动态库 Embed 属性设置为 Embed & Sign。
信息
声网 SDK 默认使用 libc++ (LLVM),如需使用 libstdc++ (GNU),请联系 sales@shengwang.cn。SDK 提供的库是 FAT Image,包含 32/64 位模拟器、32/64 位真机版本。
-
在 Xcode 中,进入 File > Swift Packages > Add Package Dependencies...,粘贴如下 URL:
Text // 对于 4.6.0 及之后的版本 github:git@github.com:Shengwang-Lab/ShengwangRtcEngine_iOS.git // 对于 4.6.0 之前的版本 https://github.com/AgoraIO/AgoraRtcEngine_iOS.git -
在 Choose Package Options 中指定你想集成的 SDK 版本。你也可以参考 Apple 官方文档进行设置。
注意
自 4.5.0 起,RTC SDK 和 RTM SDK (2.2.0 及以上版本) 都包含 aosl.xcframework 库。如果你通过 CDN 手动集成 RTC SDK 且同时集成了 RTM SDK,为避免冲突,请手动删除版本较低的 aosl.xcframework 库。4.6.0 RTC SDK aosl.xcframework 库版本为 1.3.0。你可以通过查看 aosl.xcframework 文件的属性来得知库的版本信息。
创建用户界面
在 ViewController.swift 文件中,为你的项目创建一个用户界面,包括本地视频窗口和远端视频窗口,分别用于展示本地视频和远端视频。如下所示:
用以下代码替换 ViewController.swift 文件中的内容,即可实时预览你创建的用户界面。
实现步骤
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
下面列出了一段实现实时互动基本流程的完整代码以供参考。复制以下代码到 ViewController.swift 文件中替换原有内容即可。
信息
在 appId、token 和 channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
导入声网组件
在 ViewController.swift 文件中引入 AgoraRtcKit。
import AgoraRtcKit初始化引擎
调用 sharedEngineWithConfig 方法,创建并初始化 AgoraRtcEngineKit。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
// 在这里输入你在声网控制台中获取的 App ID
agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId:<#Your App ID#>, delegate: self)启用视频模块
按照以下步骤启用视频模块。
- 调用
enableVideo方法,启用视频模块。 - 调用
setupLocalVideo方法初始化本地视图,同时设置本地的视频显示属性。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
agoraKit.enableVideo()
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.view = localView
videoCanvas.renderMode = .hidden
// 设置本地视图
agoraKit.setupLocalVideo(videoCanvas)
// 开始本地视频预览
agoraKit.startPreview()加入频道并发布音视频流
调用 joinChannelByToken[2/4] 方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
let options = AgoraRtcChannelMediaOptions()
// 设置频道场景为直播
options.channelProfile = .liveBroadcasting
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
options.clientRoleType = .broadcaster
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true
// 发布摄像头采集的视频
options.publishCameraTrack = true
// 自动订阅所有音频流
options.autoSubscribeAudio = true
// 自动订阅所有视频流
options.autoSubscribeVideo = true
// 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
// uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调
agoraKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)设置远端用户视图
调用 setupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 didJoinedOfUid 回调获取远端用户的 uid。
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int){
// 当远端用户加入频道后,显示指定 uid 的远端视频流
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = remoteView
videoCanvas.renderMode = .hidden
agoraKit.setupRemoteVideo(videoCanvas)
}实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示了如何实现 didJoinChannel 和 didOfflineOfUid 回调。
// 成功加入频道回调
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
print("didJoinChannel: \(channel), uid: \(uid)")
}
// 远端用户或主播离开当前频道回调
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = nil
agoraKit.setupRemoteVideo(videoCanvas)
}开始音视频互动
当视图加载完成后,在 viewDidLoad 中调用一系列方法加入频道,开始音视频互动。
override func viewDidLoad() {
super.viewDidLoad()
// 当加载视图后,你可以进行其他其他设置
// 当调用声网 API 时,以下函数会被调用
agoraKit.enableVideo()
startPreview()
joinChannel()
}结束音视频互动
-
调用
leaveChannel方法离开频道,与会话相关的资源也会被释放。Swift agoraKit.stopPreview() agoraKit.leaveChannel(nil) -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。Swift AgoraRtcEngineKit.destroy()警告
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
调试 App
参考以下步骤来测试你的 App:
-
将 iOS 设备连接至计算机。
-
点击 Build 来运行你的项目,需等待几秒至 App 安装完成。
-
允许 App 访问设备的麦克风和摄像头权限。
-
(可选)如果设备上弹出不受信任的开发者提示,则首先点击取消关闭该提示,然后在 iOS 设备上打开设置 > 通用 > VPN 与设备管理,在开发者 APP 中选择信任该开发者。
-
使用第二台 iOS 设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:
- 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
- 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
AgoraAudienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 如何处理 CocoaPods 常见问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 如何处理无声问题?
- 为什么部分 iOS 版本 App 锁屏或切后台后音视频采集无效?
- 为什么 SDK 中使用的是动态库而不是静态库?
- 如何增加隐私清单?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- Xcode 12.0 或以上版本。
- Apple 开发者账号。
- 如需使用 Cocoapods 集成 SDK,则确保已安装 Cocoapods,否则请参考 Getting Started with CocoaPods 进行安装。
- 两台 macOS 10.10 或以上版本的设备。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
按照以下步骤,在 Xcode 中创建一个项目:
-
参考 Create a project 创建一个新的项目。Application 选择 App,Interface 选择 Storyboard,Language 选择 Swift。
信息
如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登入 Apple ID,点击 Next,完成后即可选择你的 Apple 账户作为开发团队。
-
为你的项目设置自动签名。
-
设置部署你的 App 的目标设备。
-
添加项目的设备权限。
在项目导航栏中打开 info.plist 文件,编辑属性列表,添加以下属性:
注意
- 下表中列出的权限均为可选权限。但如果不添加所列权限,你将无法使用麦克风和摄像头进行实时音视频互动。
- 如果你的项目中需要添加第三方插件或库(例如第三方摄像头),且该插件或库的签名与项目的签名不一致,你还需勾选 Hardened Runtime > Runtime Exceptions 中的 Disable Library Validation。
- 更多注意事项,可以参考 Preparing Your App for Distribution。
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | 使用麦克风的目的,例如:for a call or live interactive streaming。 |
| Privacy - Camera Usage Description | String | 使用摄像头的目的,例如:for a call or live interactive streaming。 |
进入 TARGETS > Project Name > Signing & Capabilities,在 App Sandbox 和 Hardened Runtime 中添加如下权限:
| Capability | Category | Permission |
|---|---|---|
| App Sandbox | Network |
|
| App Sandbox | Hardware |
|
| Hardened Runtime | Resource Access |
|
集成 SDK
根据实际情况,在以下集成方式中任选一种,在你的项目中集成 SDK。
-
在终端里进入项目根目录,并运行
pod init命令。项目文件夹下会生成一个Podfile文本文件。 -
打开
Podfile文件,修改文件为如下内容。注意将Your App替换为你的 Target 名称。Ruby platform :macos, '10.11' target 'Your App' do # 对于 4.6.0 及之后的版本 # x.y.z 请填写具体的 SDK 版本号,如 4.6.0。可通过发版说明获取最新版本号 pod 'ShengwangRtcEngine_macOS', 'x.y.z' # 对于 4.6.0 之前的版本 # x.y.z 请填写具体的 SDK 版本号,如 4.0.1。可通过发版说明获取最新版本号 pod 'AgoraRtcEngine_macOS', 'x.y.z' end -
在终端内运行
pod install命令安装声网 SDK。成功安装后,Terminal 中会显示Pod installation complete!。 -
成功安装后,项目文件夹下会生成一个后缀为
.xcworkspace的文件,通过 Xcode 打开该文件进行后续操作。
-
前往下载页面,获取最新版的 SDK,然后解压。
-
将 SDK 包内
libs路径下的文件,拷贝到你的项目路径下。 -
打开 Xcode,添加对应动态库,确保添加的动态库 Embed 属性设置为 Embed & Sign。
信息
声网 SDK 默认使用 libc++ (LLVM),如需使用 libstdc++ (GNU),请联系 sales@shengwang.cn。SDK 提供的库是 FAT Image,包含 32/64 位模拟器、32/64 位真机版本。
-
在 Xcode 中,进入 File > Swift Packages > Add Package Dependencies...,粘贴如下 URL:
Text // 对于 4.6.0 及之后的版本 github:git@github.com:Shengwang-Lab/ShengwangRtcEngine_macOS.git // 对于 4.6.0 之前的版本 https://github.com/AgoraIO/AgoraRtcEngine_macOS.git -
在 Choose Package Options 中指定你想集成的 SDK 版本。你也可以参考 Apple 官方文档进行设置。
注意
自 4.5.0 起,RTC SDK 和 RTM SDK (2.2.0 及以上版本) 都包含 aosl.xcframework 库。如果你通过 CDN 手动集成 RTC SDK 且同时集成了 RTM SDK,为避免冲突,请手动删除版本较低的 aosl.xcframework 库。4.6.0 RTC SDK aosl.xcframework 库版本为 1.3.0。你可以通过查看 aosl.xcframework 文件的属性来得知库的版本信息。
创建用户界面
根据使用场景,为你的项目创建一个用户界面,包括本地视频窗口和远端视频窗口。用以下代码替换 ViewController.swift 文件中的内容:
import Cocoa
import AgoraRtcKit
class ViewController: NSViewController {
// 本地视频视图
var localView: NSView!
// 远端视频视图
var remoteView: NSView!
// RTC 引擎
var agoraKit: AgoraRtcEngineKit!
override func viewDidLayout() {
super.viewDidLayout()
// 计算本地视图的位置和大小
let localViewWidth: CGFloat = 135
let localViewHeight: CGFloat = 240
let localViewX: CGFloat = 2
let localViewY: CGFloat = 2
// 设置本地视图的 frame
localView.frame = CGRect(x: localViewX, y: localViewY, width: localViewWidth, height: localViewHeight)
// 设置远端视图的 frame,让它充满整个 CustomView
remoteView.frame = view.bounds
}
}实现步骤
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
下面列出了一段实现实时互动基本流程的完整代码以供参考。复制以下代码到 ViewController.swift 文件中替换原有内容即可。
信息
在 appId、token 和 channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
导入声网组件
在 ViewController.swift 文件中引入 AgoraRtcKit。
import AgoraRtcKit初始化引擎
调用 sharedEngineWithConfig 方法,创建并初始化 AgoraRtcEngineKit。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)启用视频模块
按照以下步骤启用视频模块。
- 调用
enableVideo方法,启用视频模块。 - 调用
setupLocalVideo方法初始化本地视图,同时设置本地视频的显示属性。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
agoraKit.enableVideo()
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = 0
videoCanvas.renderMode = .hidden
videoCanvas.view = localView
// 设置本地视图
agoraKit.setupLocalVideo(videoCanvas)
// 开始本地视频预览
agoraKit.startPreview()加入频道并发布音视频流
调用 joinChannelByToken[2/4] 方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
let options = AgoraRtcChannelMediaOptions()
// 设置频道场景为直播
options.channelProfile = .liveBroadcasting
// 设置用户角色为主播
// 如果要将用户角色设置为观众,则修改下一行代码为 options.clientRoleType = .audience
options.clientRoleType = .broadcaster
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true
// 发布摄像头采集的视频
options.publishCameraTrack = true
// 自动订阅所有音频流
options.autoSubscribeAudio = true
// 自动订阅所有视频流
options.autoSubscribeVideo = true
// 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
// uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调
agoraKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)设置远端用户视图
调用 setupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 didJoinedOfUid 回调获取远端用户的 uid。
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int){
// 当远端用户加入频道后,显示指定 uid 的远端视频流
print("User \(uid) joined after \(elapsed) milliseconds")
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = remoteView
videoCanvas.renderMode = .hidden
agoraKit.setupRemoteVideo(videoCanvas)
}实现常用回调
根据使用场景,定义你所需的回调。以下示例代码展示了如何实现 didJoinChannel 和 didOfflineOfUid 回调。
// 成功加入频道回调
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
print("didJoinChannel: \(channel), uid: \(uid)")
}
// 远端用户或主播离开当前频道回调
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
// 打印调试信息
print("User \(uid) went offline due to \(reason)")
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.view = nil
agoraKit.setupRemoteVideo(videoCanvas)
}开始音视频互动
当视图加载完成后,在 viewDidLoad 中调用一系列方法加入频道,开始音视频互动。
override func viewDidLoad() {
super.viewDidLoad()
// 当加载视图后,你可以进行其他其他设置
// 初始化视频窗口
initView()
// 当调用声网 API 时,以下函数会被调用
agoraKit.enableVideo()
startPreview()
joinChannel()
}结束音视频互动
-
调用
leaveChannel方法离开频道,与会话相关的资源也会被释放。Swift agoraKit.stopPreview() agoraKit.leaveChannel(nil) -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。Swift AgoraRtcEngineKit.destroy()警告
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
调试 App
参考以下步骤来测试你的 App:
-
将 macOS 设备连接至计算机。
-
点击 Build 来运行你的项目,需等待几秒至 App 安装完成。
-
允许 App 访问设备的麦克风和摄像头权限。
-
使用第二台 macOS 设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:
- 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
- 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
AgoraAudienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 如何处理 CocoaPods 常见问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 编译 Xcode 项目时遇到 “无法打开 framework” 的弹窗警告怎么办?
- 如何设置日志文件?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 Web SDK,通过少量代码从 0 开始实现一个简单的实时互动 App。 开始之前,你需要首先了解音视频实时互动的相关概念和流程。
实时音视频互动主要包含互动直播和视频通话两大场景,你可以按需搭建想要的场景:
- 互动直播:频道内的用户分为主播和观众,只有主播可以自由发言并且被其他用户看见。
- 视频通话:频道内的用户不区分主播和观众,所有用户都可以发言并看见彼此。
前提条件
在集成声网实时互动 Web SDK 快速实现音视频互动前,请确保开发环境满足以下要求:
-
Windows 或 macOS 计算机,需满足以下要求:
- 下载满足声网 Web SDK 兼容性的浏览器。声网强烈推荐使用最新稳定版 Google Chrome 浏览器。
- 具备物理音视频采集设备。
- 可连接到互联网。如果你的网络环境部署了防火墙,请参考应对防火墙限制以正常使用声网服务。
- 搭载 2.2 GHz Intel 第二代 i3/i5/i7 处理器或同等性能的其他处理器。
-
有效的声网账户和声网项目,请参考开通 RTC 服务,在声网控制台注册、登录并创建声网项目,然后获取项目的 App ID 和临时 Token。
-
安装 Node.js 18 或更高版本。
信息
有些框架模板可能需要更高版本的 Node.js 才能工作,如果你的包管理器发出警告,请升级你的 Node.js 版本。
实现步骤
本节介绍如何快速搭建并实现一个实时音视频互动场景。根据你的开发偏好和需要,选择如下任意一种实现方式。
信息
使用包管理工具只能快速搭建开箱即用的视频通话场景。如果你希望体验互动直播场景,请选用获取 SDK 后手动集成的方式,并在创建客户端时将 mode 设置为 live。
1. 获取快速开始安装包 (使用包管理工具快速创建(推荐))
在使用包管理器创建项目之前,你需要通过以下任意一种途径下载声网实时互动 Web SDK 快速开始安装包资源:
通过 GitHub 下载 (通过 GitHub 下载)
下载或克隆 create-agora-app获取快速开始安装包资源。
2. 使用包管理器创建项目 (使用包管理工具快速创建(推荐))
根据你的开发需要,使用如下一款包管理工具并继续:
你可以在项目创建过程中修改你的项目名称,例如 agora-project。
3. 选择框架模板 (使用包管理工具快速创建(推荐))
在创建过程中,系统会提示你选择一个前端框架模板(包括 Vanilla-js、Vue-ts、React-ts 或 Svelte-ts)。你可以根据你的需求选择相应的框架。
4. 启动项目 (使用包管理工具快速创建(推荐))
系统将根据你的选择生成项目骨架,你需要进入项目目录并安装依赖,然后启动开发服务器。
以下是使用 yarn 创建了一个 React-ts 项目的示例,按照屏幕提示输入命令行来完成相关操作即可:
Scaffolding project in agora-project...
Done. Now run:
cd agora-project
yarn
yarn dev此时,开发服务器将启动,你可以在浏览器中访问 http://localhost:5173/ 查看项目运行情况。
信息
在本地服务器 (localhost) 运行 Web 应用仅作为测试用途。部署生产环境时,请确保使用 HTTPS 协议。
5. 查看预期效果 (使用包管理工具快速创建(推荐))
你的浏览器会自动打开以下页面:
打开摄像头和麦克风确认设备没有问题,之后根据界面提示,输入 App ID、临时 Token,以及生成临时 Token 时填入的频道名,可以快速实现加入频道、发布音视频流和离开频道等基础音视频互动功能。
信息
上图以 React-ts 框架打开的界面为例。根据你所选择的前端框架模板,浏览器打开的界面可能有所不同。
获取 SDK 后手动集成 (获取 SDK 后手动集成)
你可以参考以下步骤,获取 SDK 后进行手动集成,以搭建你想要实现的音视频互动场景(视频通话或互动直播)。
1. 创建 Web 项目 (获取 SDK 后手动集成)
创建一个名为 agora_web_quickstart 的文件夹。一个 Web 客户端项目至少需包含以下文件:
index.html: 用于设计 Web 应用的用户界面。basicEngagement.js: 通过AgoraRTCClient实现具体应用逻辑的代码。package.json: 安装并管理项目依赖。你可以通过命令行进入agora_web_quickstart目录并运行npm init命令来创建package.json文件。
2. 集成 SDK (获取 SDK 后手动集成)
参考以下步骤通过 npm 将声网 Web SDK 集成到你的项目中:
在 package.json 文件的 dependencies 字段中添加 agora-rtc-sdk-ng 及版本号:
{
"name": "agora_web_quickstart",
"version": "1.0.0",
"description": "",
"main": "basicEngagement.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"agora-rtc-sdk-ng": "latest"
},
"author": "",
"license": "ISC"
}将以下代码复制到 basicEngagement.js 文件中,在你的项目中导入 AgoraRTC 模块。
import AgoraRTC from "agora-rtc-sdk-ng"3. 实现用户界面 (获取 SDK 后手动集成)
将以下代码复制到 index.html 实现客户端用户界面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Web SDK Video Quickstart</title>
<!--
This line is used to refer to the bundle.js file packaged by webpack. A sample webpack configuration is shown in the later step of running your app.
-->
<script src="./dist/bundle.js"></script>
</head>
<body>
<h2 class="left-align">Web SDK Video Quickstart</h2>
<div class="row">
<div>
<button type="button" id="host-join">Join as host</button>
<button type="button" id="audience-join">Join as audience</button>
<button type="button" id="leave">Leave</button>
</div>
</div>
</body>
</html><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Web SDK Video Quickstart</title>
<!--
This line is used to refer to the bundle.js file packaged by webpack. A sample webpack configuration is shown in the later step of running your app.
-->
<script src="./dist/bundle.js"></script>
</head>
<body>
<h2 class="left-align">Web SDK Video Quickstart</h2>
<div class="row">
<div>
<button type="button" id="join">JOIN</button>
<button type="button" id="leave">LEAVE</button>
</div>
</div>
</body>
</html>4. 复制项目示例代码 (获取 SDK 后手动集成)
声网实时互动 Web SDK 提供两种模式的音视频互动,分别是视频通话和互动直播。两者创建客户端时设置的 mode 参数不同:
// 视频通话场景下 mode 设为 rtc
rtc.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
// 视频直播场景下 mode 设为 live
rtc.client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });你可以直接将以下代码复制到 basicEngagement.js 文件中来快速体验互动直播,注意将 appID、token 和频道名替换为你自己的 App ID 和临时 Token以及频道名。
下图展示了基础的音视频直播的 API 调用。注意图中的方法是对不同的对象调用的。
下图展示了实现音视频互动的 API 调用流程。注意图中的方法是对不同的对象调用的。
5. 测试 App (获取 SDK 后手动集成)
本文使用 webpack 打包项目,使用 webpack-dev-server 运行项目。
参考以下步骤来测试你的 App:
在 package.json 的 dependencies 字段中添加 webpack、webpack-cli 和 webpack-dev-server,并在 scripts 字段中添加 build 和 start:dev。
{
"name": "agora_web_quickstart",
"version": "1.0.0",
"description": "",
"main": "basicEngagement.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js",
"start:dev": "webpack serve --open --config webpack.config.js"
},
"dependencies": {
"agora-rtc-sdk-ng": "latest",
"webpack": "5.28.0",
"webpack-dev-server": "3.11.2",
"webpack-cli": "4.10.0"
},
"author": "",
"license": "ISC"
}在项目目录中创建一个名为 webpack.config.js 的文件,将以下代码复制到 webpack.config.js 配置 webpack:
const path = require("path");
module.exports = {
entry: "./basicEngagement.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
devServer: {
compress: true,
port: 9000,
},
};运行下列命令安装依赖:
npm install运行下列命令通过 webpack 编译项目:
# Use webpack to package the project
npm run build通过 webpack-dev-server 运行项目:
npm run start:dev信息
- 在本地服务器 (localhost) 运行 Web 应用仅作为测试用途。部署生产环境时,请确保使用 HTTPS 协议。
- 由于浏览器的安全策略,声网对除 127.0.0.1 以外的 HTTP 地址作了限制。
6. 查看预期效果 (获取 SDK 后手动集成)
你的浏览器会自动打开以下页面:
点击 Join as host 以主播角色加入频道。你还可以邀请朋友克隆 Gitee 示例项目或 GitHub 示例项目到本地,在浏览器中打开 src/index.html 文件,并输入相同的 App ID、频道名称和临时 Token。你的朋友以主播角色加入频道后,你们可以看到彼此,并听到彼此的声音;你的朋友以观众角色加入频道后,他可以看到你,并听到你的声音。
你的浏览器会自动打开以下页面:
点击 JOIN 加入频道。你还可以邀请朋友克隆 Gitee 示例项目或 GitHub 示例项目到本地,在浏览器中打开 src/index.html 文件,并输入相同的 App ID、频道名称和临时 Token。你的朋友加入频道后,你们可以看到彼此,并听到彼此的声音。
7. 后续步骤 (获取 SDK 后手动集成)
在完成音视频互动后,你可以阅读以下文档进一步了解:
- 本文的示例使用了临时 Token 加入频道。在正式生产环境中,为保障通信安全,你需要在自己的 App 服务端生成 Token。详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时实现。详见实现极速直播。
参考信息 (获取 SDK 后手动集成)
示例项目 (获取 SDK 后手动集成)
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
其它集成方式 (获取 SDK 后手动集成)
使用 npm 集成 Web SDK 还支持开启 Tree shaking 来减小集成 SDK 后的 App 体积,详见使用 Tree shaking。
除使用 npm 获取 Web SDK 之外,你还可以使用以下方法获取 SDK:
-
在项目 HTML 文件中,添加如下代码,使用 CDN 方法获取 SDK:
HTML <script src="https://download.agora.io/sdk/release/AgoraRTC_N-4.24.9.js"></script> -
下载声网 Web SDK 4.x 版本 SDK 包至本地,将 SDK 包中的
.js文件保存到项目文件所在的目录下,然后在项目 HTML 文件中添加如下代码:HTML <script src="./AgoraRTC_N-4.24.9.js"></script>
信息
在以上方法中,SDK 都会在全局导出一个 AgoraRTC 对象,直接访问这个对象即可操作 SDK。
常见问题 (获取 SDK 后手动集成)
为什么在本地运行快速开始项目时会报错 digital envelope routines::unsupported?
本文中的快速开始项目通过 webpack 打包并在本地运行。由于 Node.js 16 及以上版本更改了对 OpenSSL 的依赖(详见 node issue),影响了项目中本地开发环境的依赖(详见 webpack issue),运行项目会发生错误。解决方案如下:
-
(推荐)运行如下命令,设置临时的环境变量:
Shell export NODE_OPTIONS=--openssl-legacy-provider -
暂时换用低版本的 Node.js。
尝试以上解决方案后,再次尝试运行项目。
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- Windows 7 或以上版本的设备。
- Microsoft Visual Studio 2017 或以上版本。
- C++ 11 或以上版本。
- 如果使用 C# 开发,还需要 .NET 桌面开发组件。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目 (C++)
以 Windows 11 为例,参考以下操作或官方文档在 Visual Studio 2022 中创建一个项目来实现实时音视频互动功能,如果你已有自己的项目,可跳过这一步骤。
-
在 Visual Studio 中,选择文件 > 新建 > 项目 来创建一个新项目。在弹出的窗口中,选择 MFC 应用作为项目模板,点击下一步将项目名称设为 AgoraQuickStart 并设置项目储存位置,然后点击创建。
-
在弹出的 MFC 应用程序窗口中,将应用程序类型设为基于对话框,将使用 MFC 设为在共享 DLL 中使用 MFC。进入生成的类,将生成的类设为 Dlg,将基类设为 CDialog,最后点击完成。
集成 SDK (C++)
- 从下载获取最新的 Windows SDK,解压并打开。
- 打开已下载的 SDK 文件,并将其中的
sdk文件夹复制到你的项目路径下。保证sdk文件夹和你的sln文件处于同一目录。
注意
自 4.5.0 起,RTC SDK 和 RTM SDK (2.2.0 及以上版本) 都包含 libaosl.dll 库。如果你通过 CDN 手动集成 RTC SDK 且同时集成了 RTM SDK,为避免冲突,请手动删除版本较低的 libaosl.dll 库。4.6.0 RTC SDK libaosl.dll 库版本为 1.3.0。你可以通过查看 libaosl.dll 文件的属性来得知库的版本信息。
配置项目属性 (C++)
在解决方案资源管理器窗口中,右击项目名称并点击属性进行以下配置:
-
进入 C/C++ > 常规 > 附加包含目录菜单,输入
$(SolutionDir)sdk\high_level_api\include。 -
进入链接器 > 常规 > 附加库目录菜单,输入
$(SolutionDir)sdk\x86_64。信息
如果你是 x86 的 Windows 操作系统,请输入
$(SolutionDir)sdk\x86。 -
进入链接器 > 输入 > 附加依赖项菜单,输入
$(SolutionDir)sdk\x86_64\agora_rtc_sdk.dll.lib。信息
如果你是 x86 的 Windows 操作系统,请输入
$(SolutionDir)sdk\x86\agora_rtc_sdk.dll.lib。 -
进入高级菜单,在高级属性中,把将内容复制到 OutDir 和将 C++ 运行时复制到输出目录设为是。
-
进入生成事件 > 生成后事件 >命令行 菜单,输入
copy $(SolutionDir)sdk\x86_64\*.dll $(SolutionDir)$(Platform)\$(Configuration)。 -
完成上述配置后点击应用。
创建用户界面 (C++)
根据实时音视频互动的场景需要,你需要在你的应用中添加如下 UI:
- 展示本地视频的视图框
- 展示远端视频的视图框
- 输入频道名称的输入框
- 加入和离开频道按钮
你可以参考下列步骤来创建用户界面。
实现步骤 (C++)
本小节介绍如何实现一个实时音视频互动应用。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
以下展示实现实时互动基本流程的完整示例代码:
注意
复制完整示例代码到你的项目之后,你需要将代码中的 APP_ID 和 token 替换成你在声网控制台获取的 App ID 和临时 Token。
参考下列步骤来在你的应用中实现实时互动:
初始化引擎 (C++)
在调用其他声网 API 前,你需要调用 createAgoraRtcEngine 创建一个IRtcEngine 对象,然后调用 initialize 并传入 App ID,初始化 IRtcEngine。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
// 创建 IRtcEngine 对象
m_rtcEngine = createAgoraRtcEngine();
// 创建 IRtcEngine 上下文对象
RtcEngineContext context;
// 输入你的 App ID。你可以在声网控制台获取你的项目的 App ID
context.appId = APP_ID;
// 添加注册回调和事件
context.eventHandler = &m_eventHandler;
// 初始化
int ret = m_rtcEngine->initialize(context);
if (ret == 0) {
m_initialize = true;
} else {
m_initialize = false;
}启用视频模块 (C++)
- 调用
enableVideo方法,启用视频模块。 - 调用
setupLocalVideo初始化本地视图,同时设置本地的视频显示属性。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
m_rtcEngine->enableVideo();
...
// 设置本地视频显示属性
VideoCanvas canvas;
// 设置视频尺寸等比缩放
canvas.renderMode = RENDER_MODE_TYPE::RENDER_MODE_HIDDEN;
// 用户 ID
canvas.uid = 0;
// 视频显示窗口
canvas.view = m_staLocal.GetSafeHwnd();
m_rtcEngine->setupLocalVideo(canvas);
// 开启本地视频预览
m_rtcEngine->startPreview();加入频道并发布音视频流 (C++)
调用 joinChannel[2/2] 方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
void CAgoraQuickStartDlg::OnBnClickedBtnJoin() {
CString strChannelName;
// 获取频道名
m_edtChannelName.GetWindowText(strChannelName);
if (strChannelName.IsEmpty()) {
AfxMessageBox(_T("Fill channel name first"));
return;
}
ChannelMediaOptions option;
// 设置频道场景为直播场景
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
// 发布麦克风采集的音频流
options.publishMicrophoneTrack = true;
// 发布摄像头采集的视频流
options.publishCameraTrack = true;
// 自动订阅所有音频流
options.autoSubscribeAudio = true;
// 自动订阅所有视频流
options.autoSubscribeVideo = true;
// 填入你在控制台获取的临时 Token 加入频道
m_rtcEngine->joinChannel(token, cs2utf8(strChannelName).c_str(), 0, option);
}实现常用回调 (C++)
你可以根据需求,在初始化时实现其他功能,如注册用户加入、离开频道等回调。
class CAgoraQuickStartRtcEngineEventHandler : public IRtcEngineEventHandler {
public:
// 注册 onJoinChannelSuccess 回调
// 本地用户成功加入频道时,会触发该回调
virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) {
if (m_hMsgHanlder) {
::PostMessage(m_hMsgHanlder, WM_MSGID(EID_JOIN_CHANNEL_SUCCESS), uid, 0);
}
}
// 注册 onUserJoined 回调
// 远端主播成功加入频道时,会触发该回调
virtual void onUserJoined(uid_t uid, int elapsed) {
if (m_hMsgHanlder) {
::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_JOINED), uid, 0);
}
}
// 注册 onUserOffline 回调
// 远端主播离开频道或掉线时,会触发该回调
virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) {
if (m_hMsgHanlder) {
::PostMessage(m_hMsgHanlder, WM_MSGID(EID_USER_OFFLINE), uid, 0);
}
}
private:
HWND m_hMsgHanlder;
};设置远端视图 (C++)
当远端用户加入频道时,从远端用户加入频道的回调中获取到的远端用户的 uid,然后调用 setupRemoteVideo 设置并渲染远端视图。
LRESULT CAgoraQuickStartDlg::OnEIDUserJoined(WPARAM wParam, LPARAM lParam) {
// 远端用户加入回调
uid_t remoteUid = wParam;
if (m_remoteRender) {
return;
}
// 设置远端视频显示属性
VideoCanvas canvas;
// 设置视频尺寸等比缩放
canvas.renderMode = RENDER_MODE_TYPE::RENDER_MODE_HIDDEN;
// 远端用户 ID
canvas.uid = remoteUid;
canvas.view = m_staRemote.GetSafeHwnd();
m_rtcEngine->setupRemoteVideo(canvas);
m_remoteRender = true;
}离开频道 (C++)
根据场景需要,如关闭应用或应用切换至后台时,调用 leaveChannel 离开当前频道。
void CAgoraQuickStartDlg::OnBnClickedBtnLeave() {
// 停止本地视频预览
m_rtcEngine->stopPreview();
// 离开频道
m_rtcEngine->leaveChannel();
// 清除本地视图
VideoCanvas canvas;
canvas.uid = 0;
m_rtcEngine->setupLocalVideo(canvas);
m_remoteRender = false;
}如果你不再需要互动,调用 release 方法释放引擎资源。
注意
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
CDialog::~CDialog() {
// 在对象被销毁时释放资源
if(m_rtcEngine){
m_rtcEngine->release(true);
m_rtcEngine = NULL;
}
}调试应用 (C++)
按照以下步骤来测试你的应用:
- 在 Visual Studio 中,选择本地 Windows 调试器开始编译应用。
- 在输入框中输入你要加入的频道名,并点击加入按钮加入频道,你将在本地视图中看到自己。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。你的朋友加入频道后,你们可以听见、看见对方。
创建项目 (C#)
参考以下操作,在 Visual Studio 中创建一个 Windows 项目:
- 在 Visual Studio 上创建一个 Windows Forms 应用项目,详见 Create a Windows Forms app in Visual Studio with C#。
- 打开 Configuration Manager 窗口,在 Active solution platform 下拉菜单中选择 New,在弹出的窗口中选择 x64 或 x86 作为目标平台。
集成 SDK (C#)
使用 Visual Studio 中的 NuGet 包管理器,将 SDK 集成到项目中。详见快速入门:在 Visual Studio 中安装和使用包。
信息
你可以在 agora_rtc_sdk 中获取最新发布的 SDK 的版本信息。
创建用户界面 (C#)
为直观地体验视频通话,你需要根据应用场景创建用户界面(UI)。若你的项目中已有用户界面,可略过此步骤。
如果你想实现音视频互动,推荐在 UI 上添加以下控件:
- 本地视图窗口
- 远端视图窗口
- 加入频道按钮
- 离开频道按钮
参考以下步骤创建 UI。
-
创建 Join 和 Leave 按钮
- 在你的项目中,打开 Solution Explore 窗口,双击 Form1.cs,打开 Toolbox 窗口,选择 Button 控件,依次添加两个按钮,并将两个按钮拖放至合适位置。
- 将鼠标移至其中一个按钮上,点击鼠标右键,选中 Properties,在打开的 Properties 窗口中修改 Text 属性为 Join,修改 Name 属性为 btnJoin。
- 重复上一个步骤来修改另一个按钮的属性:修改 Text 为 Leave;修改 Name 为 btnLeave。
-
创建本地及远端视图窗口
- 打开 Toolbox 窗口,选中 PictureBox 控件,依次为本地视图和远端视图在合适的位置添加控件。
- 将鼠标移至本地视图窗口控件上,点击鼠标右键,选中 Properties,在打开的 Properties 窗口中修改 Name 属性为 videoboxLocal;修改 BorderStyle 为 FixedSingle。
- 重复上一个步骤修改远端视图窗口控件的属性:修改 Name 为 videoboxRemote;修改 BorderStyle 为 FixedSingle。
-
创建频道名输入框
- 打开 Toolbox 窗口,选中 TextBox 控件,然后将其拖拽至合适位置。
- 将鼠标移至添加好的输入框控件上,点击鼠标右键,选中 Properties ,修改其属性 Name 为 txChannelName。
-
保存上述步骤的更改。
-
分别双击 Join 和 Leave 按钮,IDE 会自动关联点击事件处理函数。
此时你的 UI 界面如下图所示:
实现步骤 (C#)
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
下面列出了一段实现实时互动基本流程的完整代码以供参考。
信息
在 APP_ID 和 Token 字段中传入你在控制台获取到的 App ID 和临时 Token。
导入声网相关的类 (C#)
导入声网 RTC SDK 相关的类。
using Agora.Rtc;初始化引擎 (C#)
调用 CreateAgoraRtcEngine 方法创建一个 RtcEngine 对象,然后调用 initialize 初始化 RtcEngine。
// 创建引擎
engine_ = RtcEngine.CreateAgoraRtcEngine();
// 配置引擎实例
RtcEngineContext ctx = new RtcEngineContext()
{
appId = APP_ID,
areaCode = AREA_CODE.AREA_CODE_GLOB,
logConfig = { filePath = "rtc.log" }
};
// 初始化引擎
var ret = engine_.Initialize(ctx);
if (ret != 0)
{
Console.WriteLine("=====>Initialize failed {0}", ret);
return;
}启用视频模块 (C#)
- 调用
EnableVideo方法,启用视频模块。 - 调用
SetupLocalVideo初始化本地视图,同时设置本地的视频显示属性。 - 调用
StartPreview方法,开启本地视频预览。
// 启用视频模块
ret = engine_.EnableVideo();
if (ret != 0)
{
Console.WriteLine("=====>EnableVideo failed {0}", ret);
}
// 设置本地视图
VideoCanvas canvas = new VideoCanvas();
canvas.view = (long)videoboxLocal.Handle;
canvas.renderMode = RENDER_MODE_TYPE.RENDER_MODE_FIT;
ret = engine_.SetupLocalVideo(canvas);
if (ret != 0)
{
Console.WriteLine("=====>SetupLocalVideo failed {0}", ret);
}
// 开启本地视频预览
ret = engine_.StartPreview(VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA_PRIMARY);
if (ret != 0)
{
Console.WriteLine("=====>StartPreview failed {0}", ret);
}
加入频道并发布音视频流 (C#)
调用 JoinChannel[2/2] 加入频道,填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
ChannelMediaOptions options = new ChannelMediaOptions();
// 设置频道场景为直播
options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
// 设置用户角色为主播
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
// 发布麦克风采集的音频流
options.publishMicrophoneTrack = true;
// 发布摄像头采集的视频流
options.publishCameraTrack = true;
// 自动订阅所有音频流
options.autoSubscribeAudio = true;
// 自动订阅所有视频流
options.autoSubscribeVideo = true;
var ret = engine_.JoinChannel(APP_TOKEN, txChannelName.Text, 0, options);设置远端用户视图 (C#)
调用 SetupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 OnUserJoined 回调获取远端用户的 uid。
private void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
{
VideoCanvas canvas = new VideoCanvas();
canvas.view = (long)videoboxRemote.Handle;
canvas.renderMode = RENDER_MODE_TYPE.RENDER_MODE_FIT;
canvas.uid = remoteUid
int ret = engine_.SetupRemoteVideo(canvas);
Console.WriteLine("----->SetupRemoteVideo, ret={0}", ret);
}实现常用回调 (C#)
根据使用场景,定义必要的回调。以下示例代码展示如何实现 OnJoinChannelSuccess、 OnUserJoined 和 OnUserOffline 回调。
public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
{
Console.WriteLine("----->OnJoinChannelSuccess channel={0} uid={1}", connection.channelId,connection.localUid);
}
public override void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
{
Console.WriteLine("----->OnUserJoined uid={0}", remoteUid);
if (EventOnUserJoined != null)
EventOnUserJoined.Invoke(connection, remoteUid, elapsed);
}
public override void OnUserOffline(
RtcConnection connection,
uint remoteUid,
USER_OFFLINE_REASON_TYPE reason
)
开始音视频互动 (C#)
在 btnJoin_Click 函数中调用 JoinChannel[2/2] 方法,当用户点击 Join 按钮时开始音视频互动。
private void btnJoin_Click(object sender, EventArgs e)
{
if (null != engine_)
{
...
var ret = engine_.JoinChannel(APP_TOKEN, txChannelName.Text, 0, options);
Console.WriteLine("=====>JoinChannel result {0}", ret);
}
}
结束音视频互动 (C#)
-
在 btnLeave_Click 函数中调用
LeaveChannel方法,当用户点击 Leave 按钮时结束音视频互动。C# private void btnLeave_Click(object sender, EventArgs e) { if (null != engine_) { var ret = engine_.StopPreview(); var ret = engine_.LeaveChannel(); Console.WriteLine("=====>LeaveChannel result {0}", ret); } } -
调用
Dispose销毁引擎,并释放声网 SDK 中使用的所有资源。C# engine_.Dispose()警告
- 调用
Dispose后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
测试你的项目 (C#)
按照以下步骤来测试你的视频通话项目:
- 将你从声网控制台获取的 App ID 和临时 Token 分别填入到
Form1.cs文件的APP_ID和APP_TOKEN中。 - 在 Visual Studio 中点击 Start 按钮运行你的项目,你将在本地视图中看到自己。
- 在输入框中输入你在声网控制台生成临时 Token 时填写的频道名,并点击 Join 按钮加入频道。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。你的朋友加入频道后,你们可以听见、看见对方。
后续步骤
- 在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- DevEco Studio 5.1.0 Release 及以上版本,已包含所需的 HarmonyOS SDK。
- 运行 API 12 及以上版本 HarmonyOS 的设备。
- 华为开发者账号。可在华为开发者联盟注册账号。
- 两台支持 HarmonyOS 的设备,建议使用 Mate 60 Pro 及更高性能的设备。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
本小节介绍如何创建项目并为项目添加体验实时互动所需的权限。
-
参考创建和运行 Hello World,创建一个新工程。
-
打开 entry/src/main 中的
module.json5文件,在module模块中声明网络和设备权限:JSON "requestPermissions": [ // 访问互联网的权限 { "name": "ohos.permission.INTERNET", "reason": "$string:Internet_reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" // 始终需要该权限 } }, // 访问麦克风的权限 { "name": "ohos.permission.MICROPHONE", "reason": "$string:Audio_reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" // 始终需要该权限 } }, // 访问摄像头的权限 { "name": "ohos.permission.CAMERA", "reason": "$string:Video_reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "inuse" // 仅在使用时需要该权限 } } ] -
打开 src/main/resources/base/element 中的
string.json文件,添加如下代码,定义所需要的权限。JSON { "name": "Internet_reason", "value": "access internet" }, { "name": "Audio_reason", "value": "access audio" }, { "name": "Video_reason", "value": "access video" }
集成 SDK
-
在下载页面下载最新版本的鸿蒙视频 SDK,并在本地解压。
-
打开解压文件,将
AgoraRtcSdk.har文件复制到项目 entry -> libs 目录下(libs 文件夹需要手动创建)。 -
在 entry 下的
oh-package.json5文件中添加如下依赖,然后点击 Sync 开始同步。JSON "dependencies": { "@shengwang/rtc-full":"file:./libs/AgoraRtcSdk.har" }
实现步骤
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程:
下面列出了一段实现实时互动基本流程的完整代码以供参考。复制以下代码到 pages/Index.ets 文件中替换原有内容,即可快速体验实时互动基础功能。
信息
在 appId、token 和 channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
处理权限请求
本小节介绍如何获取设备的摄像头、录音等权限。
-
在项目中打开 entryability ->
EntryAbility.ets文件,在EntryAbility之前添加权限申请,示例代码如下所示。启动应用程序时,检查是否已在 App 中授予了实现实时互动所需的权限。
ArkTS const permissions: Array<Permissions> = ['ohos.permission.INTERNET','ohos.permission.MICROPHONE',"ohos.permission.CAMERA"]; async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> { let atManager = abilityAccessCtrl.createAtManager(); let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; // 获取应用程序的 accessTokenID let tokenId: number = 0; try { let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; tokenId = appInfo.accessTokenId; } catch (error) { let err: BusinessError = error as BusinessError; console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`); } // 校验 App 是否被授予权限 try { grantStatus = await atManager.checkAccessToken(tokenId, permission); } catch (error) { let err: BusinessError = error as BusinessError; console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`); } return grantStatus; } export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); let context = this.context; let atManager = abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser 会判断权限的授权状态来决定是否唤起弹窗 for(let i=0;i<permissions.length;i++) { let permission: Permissions = permissions[i] let granted : boolean = false; let toGrantedPerm: Array<Permissions> = new Array<Permissions>(); toGrantedPerm.push(permission) checkAccessToken(permission).then((value)=>{ if(value == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED){ granted = true; hilog.info(0x0000, 'testTag', '%{public}s', 'Permission granted'); } else { atManager.requestPermissionsFromUser(context, toGrantedPerm).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { // 用户授权,可以继续访问目标操作 } else { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 hilog.info(0x0000, 'testTag', '%{public}s', 'Permission denied'); return; } } // 授权成功 }).catch((err: BusinessError) => { hilog.info(0x0000, 'testTag', '%{public}s',`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) } }) } } }
导入声网组件
打开 src/main/ets/pages/Index.ets 文件,导入如下所需的声网 SDK 组件。
import {
ChannelMediaOptions,
Constants,
RtcEngine,
RtcEngineConfig,
RtcStats,
VideoCanvas,
} from "@shengwang/rtc-full"添加视频渲染组件
在 Index.ets 文件中添加视频渲染组件 XComponent。
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
XComponent({
// id 必须在当前页面是唯一的
id: 'local',
// type 必须设置为 surface
type: 'surface',
// libraryname 必须设置为 Constants.AGORA_LIB_NAME
libraryname: Constants.AGORA_LIB_NAME,
})
.width('100%')
.height('100%')
.align(Alignment.TopStart)
XComponent({
id: 'remote',
type: 'surface',
libraryname: Constants.AGORA_LIB_NAME,
})
.width('100%')
.height('50%')
.margin({ bottom: 10 })
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}初始化引擎
调用 create 方法初始化 RtcEngine。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
let config:RtcEngineConfig = new RtcEngineConfig();
let context = getContext(this) as common.UIAbilityContext;
config.mContext = context;
// 在这里输入你在声网控制台中获取的 App ID
config.mAppId = "<#Your App ID#>";
config.mEventHandler = {};
// 创建并初始化 RtcEngine
this.rtcEngine = RtcEngine.create(config);启用视频模块
按照以下步骤启用视频模块:
- 调用
enableVideo方法,启用视频模块。 - 调用
setupLocalVideo方法初始化本地视图,同时设置本地的视频显示属性。 - 调用
startPreview方法,开启本地视频预览。
this.rtcEngine.enableVideo();
// 设置本地视图
// local 为用于渲染本地图像的 XComponent 的 ID
let canvas: VideoCanvas = new VideoCanvas("local");
canvas.uid = 0;
canvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
canvas.mirrorMode = VideoCanvas.VIDEO_MIRROR_MODE_ENABLED;
this.rtcEngine.setupLocalVideo(canvas);
this.rtcEngine.startPreview();加入频道并发布音视频流
调用 joinChannelWithOptions 加入频道。在 options 中进行如下配置:
- 设置频道场景为
BROADCASTING(直播场景),并将用户角色设置为BROADCASTER(主播)或AUDIENCE(观众)。 - 将
publishMicrophoneTrack和publishCameraTrack设置为true,发布麦克风采集的音频和摄像头采集的视频。 - 将
autoSubscribeAudio和autoSubscribeVideo设置为true,自动订阅所有音视频流。
let option:ChannelMediaOptions = new ChannelMediaOptions();
// 自动订阅所有音频流
option.autoSubscribeAudio = true;
// 自动订阅所有视频流
option.autoSubscribeVideo = true;
// 发布摄像头采集的视频
option.publishCameraTrack = true;
// 发布麦克风采集的音频
option.publishMicrophoneTrack = true;
// 设置频道场景为直播
option.channelProfile = Constants.ChannelProfile.LIVE_BROADCASTING;
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
option.clientRoleType = Constants.ClientRole.BROADCASTER;
// 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
// uid 为 0,表示由服务器分配 uid,分配的 uid 将通过 onJoinChannelSuccess 回调返回
this.rtcEngine.joinChannelWithOptions(<#Your Token#>, <#Your Channel Name#>, 0,option);设置远端视图
调用 setupRemoteVideo 方法初始化远端用户视图,同时设置远端用户的视图在本地显示属性。你可以通过 onUserJoined 回调获取远端用户的 uid。
config.mEventHandler.onUserJoined = (uid: number, collapse: number) => {
// 设置远端渲染
// remote 为用于渲染远端图像的 XComponent 的 ID
let canvas:VideoCanvas = new VideoCanvas('remote');
canvas.uid = uid;
this.rtcEngine!.setupRemoteVideo(canvas);
};实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示如何实现 onJoinChannelSuccess 和 onUserOffline 回调。
config.mEventHandler.onJoinChannelSuccess = (cid: string, uid: number, elapsed: number) => {
console.info("mEventHandler.onJoinChannelSuccess: " + cid + " , " + uid);
};
config.mEventHandler.onUserOffline = (uid: number, reason: number) => {
console.info("mEventHandler.onUserOffline: " + uid + " , " + reason);
};开始音视频互动
在 onClick 中调用一系列方法加载界面布局、检查 App 是否获取实时互动所需权限,并加入频道开始音视频互动。
Button("Join")
.enabled(!this.isJoined)
.fontSize(20)
.width("40%")
.margin({ left: "5%", right: "5%" })
.align(Alignment.Center)
.onClick(() => {
this.initEngineAndJoinChannel();
})结束音视频互动
按照以下步骤结束音视频互动:
-
调用
stopPreview停止视频预览。 -
调用
leaveChannel离开当前频道,释放所有会话相关的资源。 -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。注意
- 调用
destroy后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
ArkTS this.rtcEngine!.stopPreview(); this.rtcEngine!.leaveChannel(); RtcEngine.destroy(); this.rtcEngine = null; - 调用
调试 App
按照以下步骤测试直播 App:
-
开启鸿蒙 NEXT 设备的开发者选项,打开 USB 调试,通过 USB 连接线将鸿蒙 NEXT 设备接入电脑。
-
在 DevEcho Studio 中,点击 Sync and Refresh Project进行同步。
-
待同步成功后,点击 Run 'app' 开始编译。片刻后,App 便会安装到你的鸿蒙 NEXT 设备上。
-
启动 App,授予录音和摄像头权限,如果你将用户角色设置为主播,便会在本地视图中看到自己。
-
使用第二台鸿蒙 NEXT 设备,重复以上步骤,在该设备上安装 App、打开 App 加入频道,观察测试结果:
- 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
- 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。
后续步骤
在完成音视频互动后,你可以阅读以下文档进一步了解:
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为保证通信安全,声网推荐从服务器中获取 Token,详情请参考使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在实时音视频互动的基础上,通过修改观众端的延时级别为低延时 (
LOW_LATENCY) 实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分鸿蒙版本 App 锁屏或切后台音视频采集无效?
相关文档
本文介绍如何建立一个简单的项目并使用声网小程序 SDK 实现基础的视频通话。
前提条件
开始前,请确保你的开发环境满足如下条件:
-
一个经过企业认证的微信小程序账号。在调试小程序 Demo 过程中,需要使用 live-pusher 和 live-player 组件。只有特定行业的认证企业账号才可以使用这两个组件。详见小程序官网文档。
-
下载并安装最新版本的微信开发者工具。
-
参考开通 RTC 服务在控制台创建项目、获取 App ID 和临时 Token,并开通小程序服务。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致鉴权失败或无法加入频道。
-
至少一台安装有微信 App 的移动设备。
信息
在集成微信小程序组件之前,声网建议你先阅读微信小程序官方文档。
准备开发环境
1. 获取小程序组件权限
在微信公众平台的小程序开发选项中,切换到接口设置页签,打开实时播放音视频流和实时录制音视频流的开关。
2. 配置服务器域名
在小程序的开发设置里,将如下域名配到服务器域名里,其中 request 合法域名区域填入以 https 开头的域名;socket 合法域名区域填入以 wss 开头的域名。
如果你使用的 SDK 为 v2.5.3 或更高版本,你需要在 request 合法域名及 socket 合法域名中添加以下域名:
wss://miniapp.agoraio.cn
https://uap-ap-web-1.agora.io
https://uap-ap-web-2.agoraio.cn
https://uap-ap-web-3.agora.io
https://uap-ap-web-4.agoraio.cn
https://report-ad.agoralab.co
https://rest-argus-ad.agoralab.co如果你使用的 SDK 为 v2.4.6 或更低版本,你需要在 request 合法域名及 socket 合法域名中添加以下域名:
wss://miniapp.agoraio.cn
https://miniapp-1.agoraio.cn
https://miniapp-2.agoraio.cn
https://miniapp-3.agoraio.cn
https://miniapp-4.agoraio.cn3. 创建小程序
参考如下步骤创建一个新的小程序。
- 打开微信开发者工具,然后按照屏幕提示扫码登录。
- 完成登录后,点击小程序界面的 +。
- 在弹出的新建项目界面中,依次填入小程序的项目名称、本地存储目录、小程序 AppID,然后点击新建。
成功创建小程序后,微信开发者工具的左侧会显示当前小程序的界面。你还可以点击真机调试,并扫描生成的二维码,在手机上进行体验。
4. 添加微信小程序组件
在微信小程序中实现音视频功能,需要使用微信的 live-player 组件和 live-pusher 组件。详见微信小程序 API 说明。
-
live-player 组件
该组件用于实现微信小程序的实时音视频播放功能。开发者在创建该组件后,还需要在 js 文件中调用 API 接口对应的组件来实现该功能。声网小程序中,创建
live-player的示例代码如下:JavaScript <live-player id="player" src="{{rtmp 播放地址}}" mode="RTC" bindstatechange="playerStateChange" object-fit="fillCrop" /> -
live-pusher 组件
该组件用于实现微信小程序的实时音视频录制功能。开发者在创建该组件后,还需要在 js 文件中调用 API 接口对应的组件来实现该功能。声网小程序中,创建
live-pusher的示例代码如下:JavaScript <live-pusher url="{{rtmp 推流地址}}" mode="RTC" bindstatechange="recorderStateChange" />
5. 集成 SDK
你可以通过下载压缩包或 npm 任一种方式集成小程序 SDK。
-
下载声网小程序 SDK 并解压。
-
将 SDK 包中的 Agora_Miniapp_SDK_for_WeChat.js 文件复制到你的小程序项目文件夹中。
-
使用
require将小程序 SDK 导入到你的项目中:JavaScript // ..Agora_Miniapp_SDK_for_WeChat.js 为你的 js 文件本地路径 const AgoraMiniappSDK = require('..Agora_Miniapp_SDK_for_WeChat.js');
如果你使用 v2.6.0 或更高版本的小程序 SDK 以及 1.02.1808300 或更高版本的微信开发者工具,可通过 npm 安装小程序 SDK。
-
初始化项目。在你的项目根目录打开终端,运行以下命令:
Shell npm init完成后,打开你的项目文件夹中的
package.json文件。在dependencies字段中添加agora-miniapp-sdk及版本号,设为latest即使用最新版本。JSON { "name": "premium-miniapp", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "agora-miniapp-sdk": "latest" }, // 添加其他业务逻辑 } -
安装依赖。在你的项目根目录打开终端,运行以下命令:
Shell npm install -
构建 npm。在微信开发者工具中,从菜单栏选择工具 > 构建 npm。
-
导入 SDK。使用
require将小程序 SDK 导入到你的项目中:JavaScript const AgoraMiniappSDK = require("agora-miniapp-sdk");
实现音视频互动
完成上述步骤后,你可以参考下图中的业务流程图,在你的项目中实现通话功能。
信息
-2301 和 -1307 是微信小程序 live-player 和 live-pusher 组件的状态码,表示网络断连,需要自行重启。详见微信小程序 live-player 和 live-pusher 组件文档。
1. 初始化客户端对象
调用 client.init 方法创建并初始化一个用于控制通话的客户端对象。你需要将 APPID 替换为你的声网项目的 App ID。详见获取 App ID。
// Callback 形式调用
let client = new AgoraMiniappSDK.Client();
client.init(APPID () => {
Utils.log(`client init success`);
}, e => {
Utils.log(`client init failed: ${e} ${e.code} ${e.reason}`);
reject(e)
});
// Promise 形式调用
let client = new AgoraMiniappSDK.Client();
await client.init(APPID)2. 加入频道
调用 client.join 方法加入频道。
在 client.join 中你需要将 yourToken 替换成你自己生成的 Token。并填入想要加入的频道名以及用户 uid。在测试阶段,你可以直接在控制台生成临时 Token。在生产环境,我们推荐你在自己的服务端生成 Token,详见在服务端生成 Token。
// Callback 形式调用
client.join(yourToken, channel, uid, () => {
Utils.log(`client join channel success`);
}, e => {
Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
reject(e)
});
// Promise 形式调用
await client.join(yourToken, channel, uid)3. 发布本地流
成功加入频道后,就能调用 client.publish 方法将本地音视频流发布到频道中。成功发布后,SDK 会返回该路音视频流的 URL。
// Callback 形式调用
client.publish(url => {
Utils.log(`client publish success`);
resolve(url);
}, e => {
Utils.log(`client publish failed: ${e.code} ${e.reason}`);
reject(e)
});
// Promise 形式调用
const url = await client.publish()4. 订阅远端流
当远端流发布到频道时,会触发 stream-added 事件,我们需要通过 client.on 监听该事件并在回调中订阅新加入的远端流。
// Callback 形式调用
client.on("stream-added", e => {
client.subscribe(uid => {
Utils.log(`stream ${uid} subscribed successful`);
}, e => {
Utils.log(`stream subscribed failed ${e} ${e.code} ${e.reason}`);
});
});
// Promise 形式调用
client.on("stream-added", async e => {
const { url, rotation } = await client.subscribe(uid)
});当远端用户取消发布流或退出频道时,关闭及移除对应的流。
client.on("stream-removed", e => {
console.log(`stream-removed: ${JSON.stringify(e)}`)
let uid = e.uid[0];
console.log(`stream ${uid} removed`);
this.removeMedia(uid);
});5. 更多功能
在实际使用中,你还可以根据使用场景实现如下功能。
重连
如果你的项目中有切换到后台的场景需求,声网推荐调用 client.rejoin 方法做好重连机制。你需要在该方法中传入当前频道内所有用户的 uid 作为额外参数。其他参数的设置与 join 方法相同。
// Callback 形式调用
client.rejoin(yourToken, channel, uid, uids, () => {
Utils.log(`client join channel success`);
}, e => {
Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
});
// Promise 形式调用
await client.rejoin(yourToken, channel, uid, uids)完整示例代码
你可以直接参考如下示例代码,在项目中实现想要的功能。
// 以下为 callback 形式调用的完整示例代码
let client = new AgoraMiniappSDK.client();
this.client = client;
// 初始化客户端
client.init(APPID, () => {
Utils.log(`client init success`);
// 加入频道
client.join(yourToken, channel, uid, () => {
Utils.log(`client join channel success`);
// 发布本地流
if (this.isBroadcaster()) {
client.publish(url => {
Utils.log(`client publish success`);
resolve(url);
}, e => {
Utils.log(`client publish failed: ${e.code} ${e.reason}`);
reject(e)
});
} else {
resolve();
}
}, e => {
Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
reject(e)
})
}, e => {
Utils.log(`client init failed: ${e} ${e.code} ${e.reason}`);
reject(e)
});// 以下为 promise 形式调用的完整示例代码
try {
let client = new AgoraMiniappSDK.client();
// 初始化客户端
await client.init(APPID)
// 设置角色
this.role = "broadcaster"
await client.setRole(this.role)
// 加入频道
await client.join(yourToken, channel, uid)
if (this.isBroadcaster()) {
// 发布本地流
const url = await client.publish()
}
} catch (e) {
console.error(e)
}运行项目
为保证运行效果,我们建议你在真机上运行项目。完成开发后,点击微信开发者工具界面的真机调试。扫描生成的二维码,即可在手机端运行和调试项目。
参考信息
与 Native 互通
频道中有小程序 SDK 和 Native SDK 时,可以选择如下一种方式实现互通:
- Native 端在直播模式下,将用户角色设置为
AgoraClientRoleBroadcaster= 1:主播,实现互通 - Native 端在直播模式下,不设置用户角色为主播,也可以接收到小程序端的流,实现互通
小程序和 Native 互通时,Native 端视频画面可能出现上下颠倒。该问题可能是由于 Native SDK 中的 setVideoEncoderConfiguration 设置的方向模式 orientationMode 为 ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE 导致的。解决方法是,将方向模式改成 ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT 就可以解决问题。
与 Web 互通
小程序和 Web 互通时,可能出现 Web 端可以看到小程序的视频,但小程序看不到 Web 端的视频。该问题可能是由于编解码格式不被支持导致的。
Web 与小程序互通时,小程序端只支持 H264 模式的编码,不支持 VP8。将 Web SDK 的 index.html 文件修改为如下设置即可:
client = AgoraRtc.createClient({mode: "live", codec: "h264"});示例项目
声网在 GitHub 上提供一个开源的小程序实时音视频示例项目,你可以下载体验或参考源代码。
相关文档
使用微信小程序 SDK 开发过程中,你还可以参考如下文档:
- 跑通小程序示例项目
- 小程序 SDK 常见问题集:例如日志功能,通用问题,错误排查。
- SDK 错误码和警告码
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
- Node.js 6.9.1 或更高版本。
- 可以访问互联网的 Windows 或 macOS 电脑。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得以下信息:
- App ID:声网随机生成的字符串,用于识别你的项目。
- 临时 Token:Token 也称为动态密钥,在客户端加入频道时对用户鉴权。临时 Token 的有效期为 24 小时。
创建项目
在本地文件夹中为 Electron 项目新建一个目录,并在项目根目录下创建以下文件:
package.json: 用于安装和管理项目依赖项。index.html:用于设计 App 的用户界面。main.js:主进程文件。renderer.js:渲染进程文件,用于实现与声网 Electron SDK 的交互。
集成 SDK
根据实际情况,在以下集成方式中任选一种,在你的项目中集成 SDK。
- 在
package.json文件中添加以下代码:
-
macOS:
JSON { "name": "electron-demo-app", "version": "0.1.0", "author": "your name", "description": "My Electron app", "main": "main.js", "scripts": { "start": "electron ." }, "agora_electron": { "platform": "darwin", "prebuilt": true }, "dependencies": { "agora-electron-sdk": "latest" }, "devDependencies": {"electron": "latest" } } -
Windows:
JSON { "name": "electron-demo-app", "version": "0.1.0", "author": "your name", "description": "My Electron app", "main": "main.js", "scripts": { "start": "electron ." }, "agora_electron": { "platform": "win32", "prebuilt": true, "arch": "ia32" }, "dependencies": { "agora-electron-sdk": "latest" }, "devDependencies": {"electron": "latest" } }
字段的具体含义如下:
agora-electron-sdk:声网 Electron SDK 的版本号。设为latest表示获取最新版本的 SDK,其它版本可在 agora-electron-sdk 中查看。electron:Electron 的版本号,支持 5.0.0 及以上版本(包括最新版本)。如果使用搭载 M1 芯片的 macOS 设备,Electron 的版本号需要设为 11.0.0 或以上。- (可选)
platform:默认根据系统选择,macOS 为darwin,Windows 为win32。 - (可选)
prebuilt:默认设为true,防止出现 Electron 或 Node.js 版本与 SDK 不兼容的问题。 - (可选)
arch:默认根据系统选择。
注意
由于不同版本的 Electron 对本地环境的要求有差异,运行项目时可能因环境不匹配报错。声网推荐你参考 Electron 官方文档选择合适的 Electron 和 Node.js 版本。
-
在终端中进入项目根目录,运行如下命令安装依赖项:
Shell # macOS npm install # Windows npm install -D --arch=ia32 electron npm install
信息
- Windows 平台需要先运行
npm install -D --arch=ia32 electron安装 32 位的 Electron,然后运行npm install。否则会收到报错:Not a valid win32 application。- 如果项目根目录下已有
node_modules文件夹,建议先删除该文件夹,再运行npm install,以免出现报错。
- 如果项目根目录下已有
除了使用 npm 集成以外,你也可以进入 Electron-SDK 手动编译最新的 SDK,集成到应用中。
创建用户界面
在 index.html 文件中添加以下代码,创建一个只包含本地视频窗口和远端视频窗口的用户界面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Electron Quickstart</title>
</head>
<body>
<h1>Electron Quickstart</h1>
<!--在界面中添加本地视频窗口 -->
<div
id="join-channel-local-video"
style="width: 300px; height: 300px; float: left"
></div>
<!--在界面中添加远端视频窗口 -->
<div
id="join-channel-remote-video"
style="width: 300px; height: 300px; float: left"
></div>
</body>
<script src="./renderer.js"></script>
</html>实现步骤
本节介绍如何实现一个实时音视频互动 App。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
下面列出了实现实时音视频互动基本流程的完整代码以供参考,你可以先将 main.js 和 renderer.js 文件的全部内容分别替换为以下代码,参考测试项目中的步骤快速体验实时音视频互动的基础功能,再按照实现流程了解其中的核心 API 调用。
信息
- 将
renderer.js文件中的<-- Insert App Id -->、<-- Insert Token -->和<-- Insert Channel Name -->分别替换为你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。 - 如果你的目标平台为 macOS v10.14 及以上,还需参考获取设备权限在
main.js中补充设备权限相关代码。
设计主进程
使用 Electron 框架创建一个应用程序,实现基本的 Electron 项目主进程。主进程中的行为包括:
- 导入所需模块
- 创建浏览器窗口
- 加载
index.html文件 - 处理应用程序生命周期事件
将以下代码复制到 main.js 文件中:
const { app, BrowserWindow } = require("electron");
const path = require("path");
// 如果使用 Electron 9.x 及以上版本,需要将 allowRendererProcessReuse 设为 false
app.allowRendererProcessReuse = false;
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// preload: path.join(__dirname, "renderer.js"),
// 将 nodeIntegration 设置 true 以及 contextIsolation 设为 false
nodeIntegration: true,
contextIsolation: false,
},
});
// 加载 index.html 文件的内容
mainWindow.loadFile("./index.html");
// 开启开发者工具
mainWindow.webContents.openDevTools();
}
// 管理 Electron 应用的浏览器窗口
app.whenReady().then(() => {
createWindow();
// 如果当前没有窗口打开,则新建一个窗口(适用于 macOS)
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// 如果所有窗口都已关闭,则退出 Electron 应用(适用于 Windows)
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});获取设备权限 (macOS)
(可选)该步骤仅在目标平台为 macOS 时需要执行。macOS 自 v10.14 起,使用摄像头和麦克风前需要检查并获取设备的使用权限,你需要在主进程中调用 Electron 原生的 askForMediaAccess 方法,来向用户请求摄像头和麦克风权限。
在 main.js 文件中添加如下代码:
// 检查并获取设备权限
async function checkAndApplyDeviceAccessPrivilege() {
// 检查并获取摄像头权限
const cameraPrivilege = systemPreferences.getMediaAccessStatus('camera');
console.log(`Camera privilege before applying: ${cameraPrivilege}`);
if (cameraPrivilege !== 'granted') {
await systemPreferences.askForMediaAccess('camera');
console.log('Requested camera access from user');
}
// 检查并获取麦克风权限
const micPrivilege = systemPreferences.getMediaAccessStatus('microphone');
console.log(`Microphone privilege before applying: ${micPrivilege}`);
if (micPrivilege !== 'granted') {
await systemPreferences.askForMediaAccess('microphone');
console.log('Requested microphone access from user');
}
}
checkAndApplyDeviceAccessPrivilege();导入依赖项
在 renderer.js 中导入声网 SDK 中构建 App 所需的模块和函数。
const {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
VideoSourceType,
VideoViewSetupMode,
} = require("agora-electron-sdk");定义基本信息
传入从声网控制台获取的 App ID、临时 Token,以及生成临时 Token 时填入的频道名,用于后续初始化引擎和加入频道。
// 填入你的 App ID
const APPID = "<-- Insert App Id -->";
// 填入你的临时 Token
let token = "<-- Insert Token -->";
// 填入生成 Token 时使用的频道名
const channel = "<-- Insert Channel Name -->";
// 用户 ID,并确保其在频道内的唯一性
let uid = 123;初始化引擎
在 renderer.js 中调用 createAgoraRtcEngine 方法创建一个 RtcEngine 实例,然后调用 initialize 初始化引擎。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
let rtcEngine;
const os = require("os");
const path = require("path");
const sdkLogPath = path.resolve(os.homedir(), "./test.log");
// 创建 RtcEngine 实例
rtcEngine = createAgoraRtcEngine();
// 初始化 RtcEngine 实例
rtcEngine.initialize({
appId: APPID,
logConfig: { filePath: sdkLogPath }
});启用视频模块
按照以下步骤启用视频模块:
- 调用
enableVideo方法,启用视频模块。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
rtcEngine.enableVideo();
// 开启本地视频预览
rtcEngine.startPreview();加入频道并发布音视频流
调用 joinChannel 方法,填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并在 options 参数中设置频道场景、用户角色等信息。
// 使用临时 Token 加入频道
rtcEngine.joinChannel(token, channel, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 发布摄像头采集的视频
publishCameraTrack: true,
// 自动订阅所有音频流
autoSubscribeAudio: true,
// 自动订阅所有视频流
autoSubscribeVideo: true,
});实现常用回调
调用 registerEventHandler 方法注册以下回调事件,触发事件时使用 console.log 方法提示结果,并执行特定操作:
onJoinChannelSuccess:成功加入频道回调。本地用户加入频道后,调用setupLocalVideo设置本地视频窗口。onUserJoined:远端用户加入当前频道回调。远端用户加入频道后,调用setupRemoteVideo设置远端视频窗口。onUserOffline:远端用户离开当前频道回调。远端用户离开频道后,调用setupRemoteVideo关闭远端视频窗口。
const EventHandles = {
// 监听本地用户加入频道事件
onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
console.log('成功加入频道:' + channelId);
// 本地用户加入频道后,设置本地视频窗口
rtcEngine.setupLocalVideo({
sourceType: VideoSourceType.VideoSourceCameraPrimary,
uid: uid,
view: localVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
});
},
// 监听远端用户加入频道事件
onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
console.log('远端用户 ' + remoteUid + ' 已加入');
// 远端用户加入频道后,设置远端视频窗口
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
},
{ channelId },
);
},
// 监听用户离开频道事件
onUserOffline: ( { channelId, localUid }, remoteUid, reason ) => {
console.log('远端用户 ' + remoteUid + ' 已离开频道');
// 远端用户离开频道后,关闭远端视频窗口
rtcEngine.setupRemoteVideo(
{
sourceType: VideoSourceType.VideoSourceRemote,
uid: remoteUid,
view: remoteVideoContainer,
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
},
);
},
};
// 注册事件回调
rtcEngine.registerEventHandler(EventHandles);离开频道
根据场景需要,如关闭应用或应用切换至后台时,调用 leaveChannel 离开当前频道。
// 停止预览
rtcEngine.stopPreview();
// 离开频道
rtcEngine.leaveChannel();如果你不再需要互动,调用 release 方法释放引擎资源。
// 取消注册回调
rtcEngine.unregisterEventHandler(EventHandles);
// 销毁引擎
rtcEngine.release();警告
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
测试项目
参考以下步骤测试你的 Electron 项目:
-
确保已经在代码中传入了有效的
appId,channelName和token。详见开通 RTC 服务。 -
在终端中进入项目根目录,运行以下命令:
Shell npm start项目成功运行后,你会看到一个自动弹出的窗口,在窗口中看到本地的视频画面。
-
邀请一位朋友使用第二台设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道。
-
你的朋友成功加入后,你们可以听见、看见对方。
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
audienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- Electron 平台常见开发问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
- 运行 Electron App 时,控制台提示 “WARNING:Too many active WebGL contexts” 怎么办?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
-
已下载 Unity Hub。
-
Unity 2018.4.0 或以上版本。
-
可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
-
不同开发平台的操作系统与编译器需满足下列版本要求:
| 开发平台 | 操作系统版本 | 编译器版本 |
|---|---|---|
| Android | Android 4.1 或以上 | Android Studio 3.0 或以上 |
| iOS | iOS 9.0 或以上 | Xcode 9.0 或以上 |
| macOS | macOS 10.10 或以上 | Xcode 9.0 或以上 |
| Windows | Windows 7 或以上 | Microsoft Visual Studio 2017 或以上 |
-
一个有效的声网账号以及声网项目。请参考 开通 RTC 服务,从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
参考以下步骤或 Unity 官方文档创建一个 Unity 项目。若已有 Unity 项目,可略过此步骤至下一步集成 SDK。
- 开始前确保你已安装 Unity。若未安装,点击此处下载。
- 打开 Unity Editor,点击 New 新建一个项目。
- 依次填入以下内容后,点击 Create project 创建一个 Unity 项目。
- Project name:项目名称。
- Location:项目存储路径。
- Template:项目类型。选择 3D。
集成 SDK
参考下列步骤来集成声网实时互动 SDK:
- 前往下载页面,下载最新版的 Unity SDK。
- 下载完成后在你的 Unity 编辑器中打开下载好的 SDK 包并取消勾选不需要的插件(默认会勾选 SDK 包含的所有插件),然后点击 Import 来导入 SDK。
创建用户界面
根据应用场景为你的项目创建一个用户界面(UI)。
例如,你可以在 UI 上添加以下控件:
- 本地视图窗口
- 远端视图窗口
- 加入/离开频道按钮
创建好的用户界面如下图所示:
你可以参考以下步骤创建 UI。若你的项目中已有用户界面可略过此步骤。
实现步骤
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程:
信息
在 _appId、_token 和 _channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
导入类
新建脚本并导入 Unity 相关的类和声网 RTC Unity SDK 相关的类和接口。
-
在 Project 中,打开 Assets > Agora-Unity-RTC-SDK > Code >Rtc,右击然后选择 Create > C# Script,此时你的 Assets 中会有一个
NewBehaviourScript.cs文件,将这个文件重新命名为JoinChannelVideo.cs。后续步骤中的示例代码均指该文件中的代码。 -
将新建的脚本和 Canvas 绑定。选择
JoinChannelVideo.cs文件,将其拖至左侧的 Canvas。在 Inspector 面板中你可以看到该文件已经和 Canvas 绑定。 -
导入 Unity 相关的类。
C# using UnityEngine; using UnityEngine.UI; -
导入
Agora.Rtc命名空间,其中包含了实现实时音视频功能所需的各种类和接口。C# using Agora.Rtc;
处理权限请求
本小节介绍如何获取设备的摄像头、麦克风等权限。在 Unity 2018.3 或以上版本中,Unity 不会主动向用户获取麦克风和相机权限,因此你需要请求获取权限。
注意
Windows 系统会在应用程序首次尝试使用摄像头或麦克风等功能时,自动向用户弹出权限请求提示,因此你无需额外处理权限请求。
如果你开发的目标平台是 Android,Unity 提供了权限请求的 API CheckPermission。你可以调用该方法来获取相关权限。参考下列步骤来获取安卓权限:
-
导入 Unity 的 Android 命名空间。
C# #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) using UnityEngine.Android; #endif -
创建需要获取的权限列表,包括摄像头和麦克风。
C# #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) private ArrayList permissionList = new ArrayList() { Permission.Camera, Permission.Microphone }; #endif -
检查是否已获取权限。
C# private void CheckPermissions() { #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID) foreach (string permission in permissionList) { if (!Permission.HasUserAuthorizedPermission(permission)) { Permission.RequestUserPermission(permission); } } #endif }
如果你开发的目标平台是 iOS 或 macOS,声网 RTC Unity SDK 在 Editor 文件夹下提供一个构建后处理脚本 BL_BuildPostProcess.cs。在你将项目从 Unity Editor 中构建并导出为 iOS 项目后,该脚本会自动向 Info.plist 文件添加摄像头和麦克风权限,无需你手动处理。
定义 App ID 和 Token
传入从声网控制台获取的 App ID、临时 Token,以及生成临时 Token 时填入的频道名,用于后续初始化引擎和加入频道。
// 填入你的 App ID
private string _appID= "";
// 填入你的频道名
private string _channelName = "";
// 填入 Token
private string _token = "";初始化引擎
在调用其他声网 API 前,需要创建并初始化 IRtcEngine 实例。调用 CreateAgoraRtcEngine 来创建 IRtcEngine 实例,调用 Initialize 进行初始化。
注意
你需要在用户同意 App 的隐私政策之后再调用下列代码来初始化 SDK。
private void SetupVideoSDKEngine()
{
// 创建 IRtcEngine 实例
RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
RtcEngineContext context = new RtcEngineContext();
context.appId = _appID;
context.channelProfile = CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING;
context.audioScenario = AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT;
// 初始化 IRtcEngine
RtcEngine.Initialize(context);
}设置 UI 元素
将 UI 组件与代码进行绑定,包括加入频道、离开频道按钮的点击事件,以及本地视频显示和远端视频显示。
private void SetupUI()
{
GameObject go = GameObject.Find("LocalView");
LocalView = go.AddComponent<VideoSurface>();
go.transform.Rotate(0.0f, 0.0f, -180.0f);
go = GameObject.Find("RemoteView");
RemoteView = go.AddComponent<VideoSurface>();
go.transform.Rotate(0.0f, 0.0f, -180.0f);
go = GameObject.Find("Leave");
go.GetComponent<Button>().onClick.AddListener(Leave);
go = GameObject.Find("Join");
go.GetComponent<Button>().onClick.AddListener(Join);
}启用视频模块
按照以下步骤启用视频模块并开启本地视频预览:
- 调用
EnableVideo启用视频模块。 - 调用
StartPreview开启本地视频预览。 - 调用
SetForUser设置本地视频显示。 - 调用
SetEnable(true)渲染本地视频。
private void PreviewSelf()
{
// 启用视频模块
RtcEngine.EnableVideo();
// 开启本地视频预览
RtcEngine.StartPreview();
// 设置本地视频显示
LocalView.SetForUser(0, "");
// 渲染视频
LocalView.SetEnable(true);
}加入频道并发布音视频流
调用 JoinChannel [2/2] 加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置频道场景为
CHANNEL_PROFILE_LIVE_BROADCASTING(直播场景) 并设置用户角色设置为BROADCASTER(主播)。 - 将
publishMicrophoneTrack和publishCameraTrack设置为true,发布麦克风采集的音频和摄像头采集的视频。 - 将
autoSubscribeAudio和autoSubscribeVideo设置为true,自动订阅所有音视频流。
public void Join()
{
// 设置频道媒体选项
ChannelMediaOptions options = new ChannelMediaOptions();
// 发布麦克风采集的音频流
options.publishMicrophoneTrack.SetValue(true);
// 发布摄像头采集的视频流
options.publishCameraTrack.SetValue(true);
// 自动订阅所有音频流
options.autoSubscribeAudio.SetValue(true);
// 自动订阅所有视频流
options.autoSubscribeVideo.SetValue(true);
// 将频道场景设为直播
options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
// 将用户角色设为主播
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
// 加入频道
RtcEngine.JoinChannel(_token, _channelName, 0, options);
}实现常用回调
根据使用场景,定义必要的回调。下列示例代码展示本地用户加入频道、远端用户加入、离开频道的回调。
// 实现你自己的回调类,可以继承 IRtcEngineEventHandler 接口类实现
internal class UserEventHandler : IRtcEngineEventHandler
{
private readonly JoinChannelVideo _videoSample;
internal UserEventHandler(JoinChannelVideo videoSample)
{
_videoSample = videoSample;
}
// 本地用户成功加入频道时,会触发该回调
public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
{
}
// SDK 接收到第一帧远端视频并成功解码时,会触发 OnUserJoined 回调
public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
{
// 设置远端视频显示
_videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
// 开始视频渲染
_videoSample.RemoteView.SetEnable(true);
Debug.Log("Remote user joined");
}
// 远端用户离开当前频道时会触发该回调
public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)
{
_videoSample.RemoteView.SetEnable(false);
}
}设置远端视图
当远端用户加入频道时,触发 OnUserJoined 回调。调用 SetForUser 设置远端视频显示,调用 SetEnable(true) 渲染视频。
// SDK 接收到第一帧远端视频并成功解码时,会触发 OnUserJoined 回调
public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed) {
// 设置远端视频显示
_videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
// 开始视频渲染
_videoSample.RemoteView.SetEnable(true);
Debug.Log("Remote user joined");
}设置远端用户离开频道或掉线后停止远端视频显示。远端用户离开频道后,触发 OnUserOffline 回调。调用 SetEnable(false) 停止显示视频。
// 远端用户离开当前频道时会触发该回调
public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)
{
_videoSample.RemoteView.SetEnable(false);
Debug.Log("Remote user offline");
}开始音视频互动
在开始音频互动前,先检查是否已获取设备权限,然后在 Start 中调用一系列方法来初始化引擎、注册事件回调、加入频道,开始音频互动。
-
检查是否已获取设备权限。调用
CheckPermissions方法检查是否已获取实现音视频互动所需的权限。C# void Update() { CheckPermissions(); } -
开始音视频互动。在
Start方法中初始化引擎并开始实时音视频互动。C# void Start() { SetupVideoSDKEngine(); InitEventHandler(); SetupUI(); PreviewSelf(); }
结束音视频互动
按照以下步骤结束音视频互动:
- 调用
StopPreview停止本地视频预览。 - 调用
LeaveChannel来离开当前频道,释放所有会话相关的资源。 - 调用
SetEnable停止远端视频渲染。
public void Leave()
{
Debug.Log("Leaving _channelName");
// 离开频道
RtcEngine.LeaveChannel();
// 关闭视频模块
RtcEngine.StopPreview();
// 停止远端视频渲染
RemoteView.SetEnable(false);
}如果你想在退出时释放 IRtcEngine 内存,调用 Dispose 方法销毁 IRtcEngine。
注意
- 调用
Dispose后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
void OnApplicationQuit()
{
if (RtcEngine != null)
{
Leave();
// 销毁 IRtcEngine
RtcEngine.Dispose();
RtcEngine = null;
}
}测试你的项目
按照以下步骤来测试你的音视频互动项目:
- 在声网控制台获取一个临时 Token。请参考开通 RTC 服务获取。
- 在
JoinChannelVideo.cs中,将你的项目的 App ID、频道名以及临时 Token 分别填入到_appID、_channelName、_token之后。 - 在 Unity Editor 中,点击 Play 按钮来运行你的项目,然后点击 Join 按钮加入频道。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、Token、频道名加入频道。你的朋友加入频道后,你们可以听见、看见对方。
后续步骤
在完成音视频互动后,你可以阅读以下文档进一步了解:
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 为什么使用 Unity 4.x SDK 开发的 iOS App 上传到 App Store 会报错?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
- Flutter 2.10.5 或更高版本。
- Dart 2.14.0 或更高版本。
- 根据你的目标平台,准备对应的开发和运行环境:
| 目标平台 | 环境要求 |
|---|---|
| iOS |
|
| Android |
|
| macOS |
|
| Windows |
|
信息
- 更多环境要求细节,详见 Install Flutter。
- 你可以运行
flutter doctor命令检查开发和运行环境是否达到要求。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得以下信息:
- App ID:声网随机生成的字符串,用于识别你的项目。
- 临时 Token:Token 也称为动态密钥,在客户端加入频道时对用户鉴权。临时 Token 的有效期为 24 小时。
创建项目
根据你选用的 IDE 不同,创建 Flutter 项目有多种方式,详见 Create the app。在本文中,以在终端中运行 flutter create 命令创建 Flutter 项目为例。
# 将 <Project Name> 替换为项目名
flutter create <Project Name>集成 SDK
-
打开
pubspec.yaml文件,添加以下依赖:- 添加
agora_rtc_engine依赖项,集成声网 Flutter SDK。关于agora_rtc_engine的最新版本可以查询 https://pub.dev/packages/agora_rtc_engine - 添加
permission_handler依赖项,安装权限处理插件。
YAML environment: sdk: ">=2.12.0 <3.0.0" # 依赖项 dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.3 # 声网 Flutter SDK 依赖项,请使用最新版本的 agora_rtc_engine agora_rtc_engine: ^6.0.0 # 权限处理插件依赖项 permission_handler: ^8.3.0 - 添加
-
添加依赖并保存文件后,打开终端,在项目路径下执行以下命令获取并安装依赖:
Shell flutter pub get
创建用户界面
根据实时音视频互动的场景需要,为你的项目创建两个视图框,分别用于展示本地视频和远端视频。复制以下代码即可快速创建场景所需的用户界面。
实现步骤
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解其中的核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程:
下面列出了一段实现实时音视频互动基本流程的完整代码以供参考。复制以下代码替换 /lib/main.dart 文件的全部内容,即可快速体验实时音视频互动基础功能。
信息
将 <-- Insert App Id -->、<-- Insert Token --> 和 <-- Insert Channel Name --> 分别替换为你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
导入 package
导入构建 App 所需的 package。
import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';定义 App ID 和 Token
传入从声网控制台获取的 App ID、临时 Token,以及生成临时 Token 时填入的频道名,用于后续初始化引擎和加入频道。
// 填写声网控制台中获取的 App ID
const appId = "<-- Insert App Id -->";
// 填写声网控制台中生成的临时 Token
const token = "<-- Insert Token -->";
// 填写频道名
const channel = "<-- Insert Channel Name -->";处理权限请求
获取体验实时音视频所需的麦克风和摄像头权限。
await [Permission.microphone, Permission.camera].request();信息
如果你的目标平台是 iOS 或 macOS,需要在 Info.plist 中添加实时互动所需的权限声明如下:
- 麦克风:
key为Privacy - Microphone Usage Description,value填写使用目的,如:for a video call。 - 摄像头:
key为Privacy - Camera Usage Description,value填写使用目的,如:for a video call。
初始化引擎
调用 createAgoraRtcEngine 方法创建一个 RtcEngine 对象,然后调用 initialize 初始化引擎并设置频道场景为 channelProfileLiveBroadcasting(直播场景)。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
// 创建 RtcEngine 对象
_engine = await createAgoraRtcEngine();
// 初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景)
await _engine.initialize(const RtcEngineContext(
appId: appId,
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
));启用视频模块
按照以下步骤启用视频模块:
- 调用
enableVideo方法,启用视频模块。 - 调用
startPreview方法,开启本地视频预览。
// 启用视频模块
await _engine.enableVideo();
// 开启本地预览
await _engine.startPreview();加入频道并发布音视频流
调用 joinChannel 加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置用户角色为
clientRoleBroadcaster(主播)或clientRoleAudience(观众)。 - 将
publishMicrophoneTrack和publishCameraTrack设置为true,发布麦克风采集的音频和摄像头采集的视频。 - 将
autoSubscribeAudio和autoSubscribeVideo设置为true,自动订阅所有音视频流。
await _engine.joinChannel(
// 使用临时 Token 和频道名加入频道
token: token,
channelId: channel,
options: const ChannelMediaOptions(
// 自动订阅所有视频流
autoSubscribeVideo: true,
// 自动订阅所有音频流
autoSubscribeAudio: true,
// 发布摄像头采集的视频
publishCameraTrack: true,
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 设置用户角色为 clientRoleBroadcaster(主播)或 clientRoleAudience(观众)
clientRoleType: ClientRoleType.clientRoleBroadcaster),
// uid 为 0 表示由引擎内部随机生成用户 ID
uid: 0,
);实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示如何调用 registerEventHandler 添加并实现 onJoinChannelSuccess、 onUserJoined 和 onUserOffline 回调。
// 添加回调事件
_engine.registerEventHandler(
RtcEngineEventHandler(
// 成功加入频道回调
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
debugPrint("local user ${connection.localUid} joined");
setState(() {
_localUserJoined = true;
});
},
// 远端用户或主播加入当前频道回调
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
debugPrint("remote user $remoteUid joined");
setState(() {
_remoteUid = remoteUid;
});
},
// 远端用户或主播离开当前频道回调
onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) {
debugPrint("remote user $remoteUid left channel");
setState(() {
_remoteUid = null;
});
},
),
);设置远端视图
当远端用户加入频道时,触发 onUserJoined 回调。通过该回调获取远端用户的 uid 后,创建一个 AgoraVideoView 控件,用于显示对应远端用户的视频流。
// 生成远端视频
Widget _remoteVideo() {
if (_remoteUid != null) {
return AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: _engine,
canvas: VideoCanvas(uid: _remoteUid),
connection: const RtcConnection(channelId: channel),
),
);
} else {
return const Text(
'Please wait for remote user to join',
textAlign: TextAlign.center,
);
}
}开始音视频互动
在 initState() 方法中初始化声网音视频功能并开始实时音视频互动。
@override
void initState() {
super.initState();
initAgora();
}结束音视频互动
按照以下步骤结束音视频互动:
- 调用
leaveChannel离开当前频道,释放所有会话相关的资源。 - 调用
release销毁引擎,并释放声网 SDK 中使用的所有资源。注意
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
Future<void> _dispose() async {
await _engine.leaveChannel(); // 离开频道
await _engine.release(); // 释放资源
}调试 App
按照以下步骤测试直播 App:
-
将目标设备连接到电脑。
-
打开终端,在项目路径下执行以下命令在目标设备上运行示例项目:
Shell flutter run -
启动 App,授予麦克风和摄像头权限,如果你将用户角色设置为主播,便会在本地视图中看到自己。
-
使用第二台设备,重复以上步骤,在该设备上安装 App、打开 App 加入频道,观察测试结果:
- 如果两台设备均作为主播加入频道,则可以看到对方并且听到对方的声音。
- 如果两台设备分别作为主播和观众加入,则主播可以在本地视频窗口看到自己;观众可以在远端视频窗口看到主播、并听到主播的声音。
以 Android 设备为例,编译成功后的 App 如下图所示:
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
audienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 如何解决 Flutter 上 iOS release 包初始化时报 symbol not found 的问题?
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于互动直播和视频通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现音视频互动的基本工作流程:
-
所有用户调用
joinChannel方法加入频道,并根据需要设置用户角色:- 互动直播:如果用户需要在频道中发流,则设为主播;如果用户只需要收流,则设为观众。
- 视频通话:将所有用户的角色都设为主播。
-
加入频道后,不同角色的用户具备不同的行为:
- 所有用户默认都可以接收频道中的音视频流。
- 主播可以在频道内发布音视频流。
- 观众如果需要发流,可在频道内调用
setClientRole方法修改用户角色,使其具备发流权限。
前提条件
- 已参考 React Native 官方文档搭建好开发环境。
- macOS、Windows 或 Linux 操作系统
- Android 5.0 或以上设备
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 有效的声网账户和声网项目。请参考开通 RTC 服务,从声网控制台获取以下信息:
- App ID:声网随机生成的字符串,用于识别你的 App。
- 临时 Token:你的 App 客户端加入频道时会使用 Token 对用户进行鉴权。临时 Token 的有效期为 24 小时。
- 已参考 React Native 官方文档搭建好开发环境。
- macOS 操作系统
- iOS 9.0 或以上设备。如果你使用 React Native 0.63 或以上版本,请确保 iOS 的版本高于 10.0。
- 已安装 CocoaPods,否则请参考 Getting Started with CocoaPods 进行安装。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 有效的声网账户和声网项目。请参考开通 RTC 服务,从声网控制台获取以下信息:
- App ID:声网随机生成的字符串,用于识别你的 App。
- 临时 Token:你的 App 客户端加入频道时会使用 Token 对用户进行鉴权。临时 Token 的有效期为 24 小时。
创建项目
参考以下步骤,创建一个 React Native 项目。
-
运行以下命令,在
ProjectName处填入你的项目名称,创建并初始化一个新项目。Shell # 初始化 package.json 文件 npm init # 安装 React Native npm install react-native # 创建 React Native 项目 npx react-native init ProjectName运行完成后,会在执行该命令的路径下自动生成一个简单的示例项目。
-
执行
npx react-native run-android运行 Android 应用或执行npx react-native run-ios运行 iOS 应用。
如果配置没有问题,你可以看到模拟器被打开,App 自动安装到模拟器上并开始运行。你也可以在 Android 或 iOS 真机上运行应用,详见在设备上运行。
现在你已经成功运行了项目,可以开始尝试集成声网 SDK 并修改项目。
集成 SDK
本节介绍如何在 React Native 0.60 或以上版本集成声网 React Native SDK。
根据你的目标开发平台,执行以下步骤:
在项目根目录下,使用以下任意一种方法下载最新版的声网 React Native SDK:
-
方法一:使用 npm 下载
Shell npm i --save react-native-agora -
方法二:使用 yarn 下载
Shell # 安装 yarn npm install -g yarn # 使用 yarn 下载声网 React Native SDK yarn add react-native-agora
信息
React Native 0.60.0 或以上版本支持自动链接原生模块,请勿手动链接。详见 Autolinking。
- 在项目根目录下,使用以下任意一种方法下载最新版的声网 React Native SDK:
-
方法一:使用 npm 下载
Shell npm i --save react-native-agora -
方法二:使用 yarn 下载
Shell # 安装 yarn npm install -g yarn # 使用 yarn 下载声网 React Native SDK yarn add react-native-agora
信息
React Native 0.60.0 或以上版本支持自动链接原生模块,请勿手动链接。详见 Autolinking。
- 进入 React Native 项目自动创建的
ios文件夹,运行以下命令安装 SDK:
cd ios
npx pod-install创建用户界面
根据实时音视频互动的场景需要,为你的项目创建两个视图框,并使用 RtcSurfaceView 组件展示本地视频和远端视频,并配置加入频道和离开频道按钮。复制以下代码即可快速创建场景所需的用户界面。
实现步骤
本节介绍如何实现一个实时音视频互动 App。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程。
下面列出了一段实现实时音视频互动基本流程的完整代码以供参考,你可以先复制完整的示例代码到你的项目中,参考测试项目中的步骤快速体验实时音视频互动的基础功能,再按照实现流程了解其中的核心 API 调用。
复制以下代码替换 App.tsx 文件的全部内容,即可快速体验实时音视频互动基础功能。
信息
将 <-- Insert App Id -->、<-- Insert Token --> 和 <-- Insert Channel Name --> 分别替换为你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
导入声网组件
导入构建 App 所需的声网组件。
import {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
IRtcEngine,
RtcSurfaceView,
} from 'react-native-agora';定义基本信息
传入从声网控制台获取的 App ID、临时 Token,以及生成临时 Token 时填入的频道名,用于后续初始化引擎和加入频道。
const appId = '<-- Insert App ID -->';
const token = '<-- Insert Token -->';
const channelName = '<-- Insert Channel Name -->';
const uid = 0; // 本地用户 Uid,无需修改获取设备权限
根据你的目标平台选择获得麦克风和摄像头的使用权限的方式:
在 Android 设备上,要获得麦克风和摄像头的使用权限,需要弹出提示框供用户选择。
// 导入获取 Android 设备权限相关组件
import {PermissionsAndroid, Platform} from 'react-native';
const getPermission = async () => {
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
PermissionsAndroid.PERMISSIONS.CAMERA,
]);
}
};在 Xcode 中,打开 info.plist 文件。在右侧列表中添加如下内容,获取相应的设备权限:
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | 使用麦克风的目的,例如:for a call or live interactive streaming。 |
| Privacy - Camera Usage Description | String | 使用摄像头的目的,例如:for a call or live interactive streaming。 |
初始化引擎
调用 createAgoraRtcEngine 方法创建一个 RtcEngine 实例,然后调用 initialize 初始化引擎。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
agoraEngineRef.current = createAgoraRtcEngine();
const agoraEngine = agoraEngineRef.current;
agoraEngine.initialize({
appId: appId,
});启用视频模块
按照以下步骤启用视频模块。
- 调用
enableVideo方法,启用视频模块。 - 调用
startPreview方法,开启本地视频预览。
agoraEngine.enableVideo();
agoraEngineRef.current?.startPreview();加入频道并发布音视频流
调用 joinChannel 方法,填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并在 options 参数中设置频道场景、用户角色等信息。
if (isHost) {
// 以主播角色加入频道
agoraEngineRef.current?.joinChannel(token, channelName, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为主播
clientRoleType: ClientRoleType.ClientRoleBroadcaster
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 发布摄像头采集的视频
publishCameraTrack: true,
// 自动订阅所有音频流
autoSubscribeAudio: true,
// 自动订阅所有视频流
autoSubscribeVideo: true,
});
} else {
// 以观众角色加入频道
agoraEngineRef.current?.joinChannel(token, channelName, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为观众
clientRoleType: ClientRoleType.ClientRoleAudience,
// 不发布麦克风采集的音频
publishMicrophoneTrack: false,
// 不发布摄像头采集的视频
publishCameraTrack: false,
// 自动订阅所有音频流
autoSubscribeAudio: true,
// 自动订阅所有视频流
autoSubscribeVideo: true,
});
}实现常用回调
注册以下必要的回调事件可以在触发相应的事件时调用 showMessage 方法提示操作结果,并更新组件状态。
onJoinChannelSuccess:成功加入频道回调。onUserJoined:远端用户加入当前频道回调。onUserOffline:远端用户离开当前频道回调。
const eventHandles = useRef<IRtcEngineEventHandler>();
eventHandles.current = {
onJoinChannelSuccess: () => {
showMessage('成功加入频道:' + channelName);
setIsJoined(true);
},
onUserJoined: (_connection: RtcConnection, uid: number) => {
showMessage('远端用户 ' + uid + ' 已加入');
setRemoteUid(uid);
},
onUserOffline: (_connection: RtcConnection, uid: number) => {
showMessage('远端用户 ' + uid + '已离开频道');
setRemoteUid(0);
},
}
// 注册回调事件
agoraEngine.registerEventHandler(eventHandles.current);离开频道
调用 leaveChannel 方法离开频道、释放资源并显示文字提示。
// 调用 leaveChannel 方法离开频道
agoraEngineRef.current?.leaveChannel();
setRemoteUid(0);
setIsJoined(false);
showMessage('已离开频道');如果你不再需要互动,调用 release 方法释放引擎资源。
// 取消注册回调事件
agoraEngineRef.current?.unregisterEventHandler(eventHandles);
// 销毁引擎
agoraEngineRef.current?.release();警告
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
调试项目
-
确保已经在代码中传入了有效的
appId,channelName和token。 -
运行 App。部分模拟机可能无法支持本项目的全部功能,建议你在真机中运行该项目。
-
在 Android 设备上运行:
a. 开启 Android 设备的开发者选项,通过 USB 连接线将 Android 设备接入电脑。
b. 在项目根目录下执行
npx react-native run-android。 -
在 iOS 设备上运行:
a. 使用 Xcode 打开
ProjectName/ios/ProjectName.xcworkspace文件夹。b. 通过 USB 线将 iOS 设备接入你的电脑。
c. 在 Xcode 中,点击 Build and run 按钮。
信息
- 在 Android 或 iOS 真机上运行 App 的详细步骤,请参考 Running On Device。
- 由于声网引擎是一个本地进程,使用 Metro 打包器重新载入 App 时可能会丢失对引擎的引用,导致无法加入频道。此时可以重新启动 App 解决问题。
-
-
启动 App,点击按钮加入频道。
-
邀请一位朋友使用第二台设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道。你的朋友加入频道后,你们可以看到彼此,并听到彼此的声音。
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在实时音视频互动的基础上,通过修改观众端的延时级别为低延时 (
AudienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的实时音视频互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 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 相关的代码取消注释。 - 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得以下信息:
- App ID:声网随机生成的字符串,用于识别你的项目。
- 临时 Token:Token 也称为动态密钥,在客户端加入频道时对用户鉴权。临时 Token 的有效期为 24 小时。
- 频道名:用于标识频道的字符串。
创建项目
参考以下步骤或 Unreal 官方操作指南创建一个 Unreal 项目。若已有 Unreal 项目,可以直接查看集成 SDK。
- 打开 Unreal Engine,点击 Games。
- 依次填入以下内容后,点击 Create。
- Template:项目类型。选择 Blank。
- Project Defaults:项目默认设置。
- Language:开发语言。选择 C++。
- Target Platform:目标平台。选择 Desktop。
- Project Location:项目存储路径。
- Project Name:项目名称。
集成 SDK
- 前往下载页面,在视频 SDK 中下载最新版本的 Unreal SDK,并解压缩。
- 在你的项目根目录文件夹下,创建名为
Plugins的文件夹。 - 将 Unreal SDK 文件夹中的
AgoraPlugin拷贝到Plugins中。
创建用户界面
为直观地体验视频直播,需根据应用场景创建用户界面(UI)。
如果你想实现一个视频直播,推荐在 UI 上添加以下控件:
- 本地主播视频窗口
- 远端主播视频窗口
- 加入/离开频道按钮
参考以下步骤创建 UI。若你的项目中已有用户界面可略过此步骤。
-
创建 Widget Blueprint
在 Unreal Editor 中,点击 Content Drawer > Content,右击选择 User Interface > Widget Blueprint。将创建的 Widget Blueprint 命名为 AgoraWidget,双击 AgoraWidget 进入蓝图。
-
在 Widget Blueprint 中创建本地及远端主播视图窗口
- 创建视图画布。选择 Palette > PANEL > Canvas Panel,将其拖至 AgoraWidget 中。
-
创建本地视图窗口。选择 COMMON > Image,将其拖至 Canvas Panel 中,重命名为 LocalVideo,并调整在画布中的位置。设置示例如下:
- Position X:350
- Position Y:150
- size X:450
- Size Y:450
-
重复上述步骤创建远端视图窗口,将其命名为 RemoteVideo,并调整在画布中的位置。设置示例如下:
- Position X:1200
- Position Y:150
- size X:450
- Size Y:450
-
在 Widget Blueprint 中创建加入和离开频道按钮
-
在 AgoraWidget 中,选择 COMMON > Button,将其拖至 Canvas Panel 中,重命名为 JoinBtn,并调整按钮在画布中的位置。设置示例如下:
- Position X:300
- Position Y:700
- size X:240
- Size Y:120
-
选择 COMMON > Text,将其拖至 JoinBtn 中。选中 JoinBtn 的 Text 控件,在 Details 面板中将 Text 的文本内容修改为 Join。
-
重复上述步骤来创建一个 LeaveBtn。你可以根据自己的需求调整按钮位置。
-
-
保存上述步骤的更改。此时 Widget Blueprint 中的 UI 界面如下图所示:
-
创建 Level Blueprint,并关联已创建的 Widget Blueprint
-
在 Unreal Editor 中,点击 Content Drawer,右击选择 Level 并命名为 agoraLevel。
-
双击打开 agoraLevel,点击 Open Level Blueprint。
-
- 右击在搜索框中输入 Create Widget,选择已创建的 AgoraWidget 按照同样的方式依次创建 Event BeginPlay 和 Add to Viewport,并按照下图进行连接:
- 保存上述步骤的更改,并运行项目,此时你创建的 UI 界面如下图所示:
实现步骤
本小节介绍如何实现一个实时音视频互动 App。你可以先复制完整的示例代码到你的项目中,快速体验实时音视频互动的基础功能,再按照实现步骤了解核心 API 调用。
下图展示了使用声网 RTC SDK 实现音视频互动的基本流程:
下面列出了实现实时互动基本流程的完整代码以供参考。复制以下代码即可快速体验实时互动基础功能。
信息
在 _appID、_token 和 _channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
处理系统逻辑
本步骤介绍如何导入实现视频直播所需的 C++ 库,并获取摄像头及麦克风设备权限。
-
新建 C++ 类,生成头文件和库文件
在 Unreal Editor 中,选择 Tools > New C++ Class,然后选择 All Classes,找到 UserWidget 并命名为 AgoraWidget,点击 Create Class 创建类。 此时一个新的 C++ 类将添加到你的项目中,你可以看到一个
AgoraWidget.h文件和一个AgoraWidget.cpp文件。 -
添加声网依赖库
在
Project/Source/Project/Project.Build.cs文件中,向PublicDependencyModuleNames.AddRange()添加声网依赖库。C++ // 添加 AgoraPlugin 依赖库 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","AgoraPlugin" }); -
初始化自定义的 Widget
在
Project/Source/AgoraWidget.h文件中添加以下代码:C++ protected: // 初始化自定义的 Widget void NativeConstruct() override; -
添加系统所需权限
-
关联 C++ 类和 Widget
在 Unreal Editor 中,点击 Content Drawer,选择 Class Settings > Graph,将 Class Options 下的 Parent Class 设置为 AgoraWidget。
导入声网库
在 AgoraWidget.h 中添加如下 include 代码:
#include "AgoraPluginInterface.h"定义 App ID 和 Token
-
导入变量相关库
在
AgoraWidget.h中添加如下 include 代码:C++ #include "Components/Image.h" #include "Components/Button.h" -
创建变量,用于创建和加入频道
在
GENERATED_BODY()后添加如下代码,变量名称必须与创建 UI 的控件名称一致:C++ // 填入你的 App ID FString _appID = ""; // 填入你的频道名 FString _channelName = ""; // 填入 Token FString _token = ""; // 定义变量属性 UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) UImage* RemoteVideo = nullptr; UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) UImage* LocalVideo = nullptr; UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (BindWidget)) UButton* JoinBtn = nullptr; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (BindWidget)) UButton* LeaveBtn = nullptr; // 定义 IRtcEngine 全局变量 agora::rtc::IRtcEngine* RtcEngineProxy;
初始化引擎
在调用其他声网 API 前,需要创建并初始化 IRtcEngine 实例。在 AgoraWidget.h 和 AgoraWidget.cpp 文件中添加 SetupVideoSDKEngine 的方法和实现。示例代码如下:
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
private:
// 获取安卓权限
void CheckAndroidPermission();
// 创建并初始化 IRtcEngine
void SetupVideoSDKEngine();// 在 #include "AgoraWidget.h" 后添加代码
void UAgoraWidget::SetupVideoSDKEngine()
{
agora::rtc::RtcEngineContext RtcEngineContext;
RtcEngineContext.appId = TCHAR_TO_ANSI(*_appID);
RtcEngineContext.eventHandler = this;
// 创建 IRtcEngine 实例
RtcEngineProxy = agora::rtc::ue::createAgoraRtcEngine();
// 初始化 IRtcEngine
RtcEngineProxy->initialize(RtcEngineContext);
}引用 UI 元素
在 AgoraWidget.h 和 AgoraWidget.cpp 文件中的 SetupVideoSDKEngine() 后添加设置 UI 元素的方法和实现。示例代码如下:
private:
// 获取安卓权限
void CheckAndroidPermission();
// 创建并初始化 IRtcEngine
void SetupVideoSDKEngine();
// 设置 UI 元素
void SetupUI();void UAgoraWidget::SetupUI()
{
JoinBtn->OnClicked.AddDynamic(this, &UAgoraWidget::Join);
LeaveBtn->OnClicked.AddDynamic(this, &UAgoraWidget::Leave);
}加入和离开频道
在 AgoraWidget.h 和 AgoraWidget.cpp 文件中添加本地用户加入和离开频道的方法和实现。示例代码如下:
// 在 UPROPERTY 后添加如下代码:
UFUNCTION(BlueprintCallable)
void Join();
UFUNCTION(BlueprintCallable)
void Leave();// 在 SetupUI() 后添加如下代码:
void UAgoraWidget::Join()
{
// 启用视频模块
RtcEngineProxy->enableVideo();
// 设置频道媒体选项
agora::rtc::ChannelMediaOptions options;
// 自动订阅所有音频流
options.autoSubscribeAudio = true;
// 自动订阅所有视频流
options.autoSubscribeVideo = true;
// 发布摄像头采集的视频
options.publishCameraTrack = true;
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true;
// 将频道场景设为直播
options.channelProfile = agora::CHANNEL_PROFILE_TYPE::CHANNEL_PROFILE_LIVE_BROADCASTING;
// 将用户角色设为主播或观众
options.clientRoleType = agora::rtc::CLIENT_ROLE_TYPE::CLIENT_ROLE_AUDIENCE;
// 加入频道
RtcEngineProxy->joinChannel(TCHAR_TO_ANSI(*_token), TCHAR_TO_ANSI(*_channelName), 0, options);
}
void UAgoraWidget::Leave()
{
// 离开频道
RtcEngineProxy->leaveChannel();
}实现回调
设置本地用户和远端主播加入和离开频道后的视频显示。在 AgoraWidget.h 和 AgoraWidget.cpp 文件中添加回调的方法和实现。示例代码如下:
// 在 agora::rtc::IRtcEngine* RtcEngineProxy; 后添加如下代码:
// 本地用户离开频道时,会触发该回调
void onLeaveChannel(const agora::rtc::RtcStats& stats) override;
// 远端主播加入频道时,会触发该回调
void onUserJoined(agora::rtc::uid_t uid, int elapsed) override;
// 远端主播离开频道时,会触发该回调
void onUserOffline(agora::rtc::uid_t uid, agora::rtc::USER_OFFLINE_REASON_TYPE reason) override;
// 本地用户加入频道时,会触发该回调
void onJoinChannelSuccess(const char* channel, agora::rtc::uid_t uid, int elapsed) override;// 在 SetupVideoSDKEngine() 后添加如下代码:
// 设置远端主播加入频道后触发的回调
void UAgoraWidget::onUserJoined(agora::rtc::uid_t uid, int elapsed)
{
// 设置远端视频显示
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = RemoteVideo;
videoCanvas.uid = uid;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_REMOTE;
agora::rtc::RtcConnection connection;
connection.channelId = TCHAR_TO_ANSI(*_channelName);
((agora::rtc::IRtcEngineEx*)RtcEngineProxy)->setupRemoteVideoEx(videoCanvas, connection);
}
// 设置远端主播离开频道时触发的回调
void UAgoraWidget::onUserOffline(agora::rtc::uid_t uid, agora::rtc::USER_OFFLINE_REASON_TYPE reason)
{
// 设置远端视频显示
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = nullptr;
videoCanvas.uid = uid;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_REMOTE;
agora::rtc::RtcConnection connection;
connection.channelId = TCHAR_TO_ANSI(*_channelName);
((agora::rtc::IRtcEngineEx*)RtcEngineProxy)->setupRemoteVideoEx(videoCanvas, connection);
}
// 设置本地用户加入频道时触发的回调
void UAgoraWidget::onJoinChannelSuccess(const char* channel, agora::rtc::uid_t uid, int elapsed)
{
AsyncTask(ENamedThreads::GameThread, [=]()
{
UE_LOG(LogTemp, Warning, TEXT("JoinChannelSuccess uid: %u"), uid);
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = LocalVideo;
videoCanvas.uid = 0;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_CAMERA;
RtcEngineProxy->setupLocalVideo(videoCanvas);
});
}
// 设置本地用户加入频道时触发的回调
void UAgoraWidget::onLeaveChannel(const agora::rtc::RtcStats& stats)
{
AsyncTask(ENamedThreads::GameThread, [=]()
{
agora::rtc::VideoCanvas videoCanvas;
videoCanvas.view = nullptr;
videoCanvas.uid = 0;
videoCanvas.sourceType = agora::rtc::VIDEO_SOURCE_TYPE::VIDEO_SOURCE_CAMERA;
RtcEngineProxy->setupLocalVideo(videoCanvas);
});
}清理所有会话相关的资源
离开频道后,如果你想退出应用或者释放 IRtcEngine 内存,需调用 release 方法销毁 IRtcEngine。在 AgoraWidget.h 和 AgoraWidget.cpp 文件中的 NativeConstruct() 后添加 NativeDestruct() 的方法和实现。
注意
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
void NativeDestruct() override;// AgoraWidget.cpp
void UAgoraWidget::NativeDestruct()
{
Super::NativeDestruct();
if (RtcEngineProxy != nullptr)
{
RtcEngineProxy->unregisterEventHandler(this);
RtcEngineProxy->release();
delete RtcEngineProxy;
RtcEngineProxy = nullptr;
}
}测试你的项目
按照以下步骤来测试你的视频直播项目:
- 在
AgoraWidget.h中,将你的项目的 App ID、频道名以及临时 Token 分别填入到_appID、_channelName、_token之后。 - 在 Unreal Editor 中,点击播放按钮来运行你的项目,然后点击 Join 来加入直播。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。如果你的朋友以主播身份加入,你们可以听见、看见对方;如果作为观众加入,你只能看到自己,你的朋友可以看到你并听到你的声音。
后续步骤
- 如果你的目标平台是 macOS 或 iOS,则需要在打包时添加实时互动所需的摄像头和麦克风等权限,详见如何为 Unreal Engine 项目添加实时互动所需的权限?
- 在本文示例中,使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理视频黑屏问题?
- 为什么我无法打开摄像头?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
- 为什么 SDK 中使用的是动态库而不是静态库?
相关文档
本文介绍如何集成声网实时互动 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 相关的代码取消注释。 - 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得以下信息:
- 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 | 自定义 |
|
| 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 | 成功加入频道回调。 |
|
FOnLeaveChannel | 离开频道回调。 | stats: 通话的统计数据。详见 FRtcStats。 |
FOnUserJoined | 远端观众或主播加入当前频道回调。 |
|
FOnUserOffline | 远端观众或主播离开当前频道回调。 |
|
创建 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 中使用的是动态库而不是静态库?
相关文档
本文介绍如何使用声网 RTC React SDK 提供的组件和 Hooks,通过少量代码从 0 开始实现一个简单的实时互动 App,适用于视频通话场景。
前提条件
开始之前你需要满足以下前提条件:
- 创建一个声网项目,并获取 App ID、频道名和临时 Token,详见开通 RTC 服务。
- 了解 React 基础知识。
立即体验
在 CodeSandbox 上,只需简单几步就能立即体验完整代码的运行效果。
具体步骤:
- 填入你获取的 App ID、频道名、临时 Token。
- 点击 Join Channel 按钮。你可以在视频画面中看到自己。
- 请一位朋友在浏览器中打开相同的页面链接,重复步骤 1 和 2 并确保填入和你相同的 App ID、频道名和临时 Token。成功加入频道后,你们可以看到和听到对方。
- 点击左下角的麦克风和摄像头按钮即可关闭或打开对应设备,点击右下角的挂断按钮即可结束通话。
你还可以直接修改左侧编辑器的代码,在右侧实时预览运行效果。
信息
如果 CodeSandbox 访问速度较慢,请尝试更改你的网络配置。
实现步骤
本节将分步骤介绍如何实现一个简单的视频通话 App。
安装依赖
npm install agora-rtc-react初始化 SDK
首先调用 Web SDK 提供的 createClient 方法创建 client 对象,用于 <AgoraRTCProvider /> 组件。
然后使用 <AgoraRTCProvider /> 组件包裹 <App /> 组件,方便后续使用状态和操作相关的 Hooks。
import React, { StrictMode } from 'react';
import { createRoot } from "react-dom/client";
import AgoraRTC, { AgoraRTCProvider } from "agora-rtc-react";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
// 视频通话场景下,将 mode 设为 "rtc"
const client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
root.render(
<StrictMode>
<AgoraRTCProvider client={client}>
<App />
</AgoraRTCProvider>
</StrictMode>
);加入频道
在 <App /> 组件中,我们再创建一个 <Basics /> 组件,实现音视频通话的逻辑。
首先使用 useJoin 这个 Hook 来加入频道,其中传入的 joinOptions 包含以下字段,获取方式详见开通 RTC 服务:
appid:标识你在声网控制台创建的项目。channel:标识用户所在的频道。频道是用于传输数据的通道,在同一个频道内的用户可以进行实时互动。token:在加入频道时用于校验用户权限的一组字符串。快速开始阶段可以使用临时 Token。
这些字段将通过表单的形式向用户收集。收集到字段后,还需要提供一个按钮给用户点击,表示准备好加入频道。
import {
LocalUser,
RemoteUser,
useIsConnected,
useJoin,
useLocalMicrophoneTrack,
useLocalCameraTrack,
usePublish,
useRemoteUsers,
} from "agora-rtc-react";
import React, { useState } from "react";
import "./styles.css";
import logo from "./logo.png";
export const Basics = () => {
// 定义状态变量
const [calling, setCalling] = useState(false); // 是否正在呼叫
const [appId, setAppId] = useState(""); // 存储 App ID 的状态
const [channel, setChannel] = useState(""); // 存储频道名的状态
const [token, setToken] = useState(""); // 存储 Token 的状态
// 使用 App ID、频道名和 Token 加入频道,是否加入频道取决于 calling 的状态
useJoin({appid: appId, channel: channel, token: token ? token : null}, calling);
return (
<>
<div className="room">
<div className="join-room">
<img alt="agora-logo" className="logo" src={logo} />
<input
onChange={e => setAppId(e.target.value)}
placeholder="<Your App ID>"
value={appId}
/>
<input
onChange={e => setChannel(e.target.value)}
placeholder="<Your channel Name>"
value={channel}
/>
<input
onChange={e => setToken(e.target.value)}
placeholder="<Your token>"
value={token}
/>
<button
className={`join-channel ${!appId || !channel ? "disabled" : ""}`}
disabled={!appId || !channel}
onClick={() => setCalling(true)}
>
<span>Join Channel</span>
</button>
</div>
</div>
</>
);
};
export default Basics;接下来可以给 <Basics /> 组件添加 CSS 样式。示例项目中使用 styles.css,加入频道界面的效果如下:
现在 App 已经实现了用户加入频道的功能和界面,但用户无法听到和看到对方,还不能进行通话。
渲染本地和远端的音视频
为了让用户能互相看到和听到对方,App 需要渲染本地用户和远端用户的音视频。
渲染本地用户音视频的步骤如下:
- 使用
useLocalMicrophoneTrack和useLocalCameraTrack创建麦克风音频轨道和摄像头视频轨道。 - 使用
usePublish发布本地用户的音频和视频轨道。 - 使用
<LocalUser />组件渲染本地用户的音频和视频。
渲染远端用户音视频的步骤如下:
- 使用
useRemoteUsers获取所有远端用户。 - 使用
<RemoteUser />组件渲染每一位远端用户的音频和视频。
此外,你还可以在界面上提供以下按钮:
- 打开/关闭麦克风。
- 打开/关闭摄像头。
- 结束通话。
export const Basics = () => {
const [calling, setCalling] = useState(false);
const [appId, setAppId] = useState("");
const [channel, setChannel] = useState("");
const [token, setToken] = useState("");
useJoin({appid: appId, channel: channel, token: token ? token : null}, calling);
// 本地用户
const [micOn, setMic] = useState(true);
const [cameraOn, setCamera] = useState(true);
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
const { localCameraTrack } = useLocalCameraTrack(cameraOn);
usePublish([localMicrophoneTrack, localCameraTrack]);
// 远端用户
const remoteUsers = useRemoteUsers();
return (
<>
<div className="room">
<div className="user-list">
<div className="user">
<LocalUser
audioTrack={localMicrophoneTrack}
cameraOn={cameraOn}
micOn={micOn}
videoTrack={localCameraTrack}
cover="https://www.agora.io/en/wp-content/uploads/2022/10/3d-spatial-audio-icon.svg"
>
<samp className="user-name">You</samp>
</LocalUser>
</div>
{remoteUsers.map((user) => (
<div className="user" key={user.uid}>
<RemoteUser cover="https://www.agora.io/en/wp-content/uploads/2022/10/3d-spatial-audio-icon.svg" user={user}>
<samp className="user-name">{user.uid}</samp>
</RemoteUser>
</div>
))}
</div>
</div>
<div className="control">
<div className="left-control">
<button className="btn" onClick={() => setMic(a => !a)}>
<i className={`i-microphone ${!micOn ? "off" : ""}`} />
</button>
<button className="btn" onClick={() => setCamera(a => !a)}>
<i className={`i-camera ${!cameraOn ? "off" : ""}`} />
</button>
</div>
<button
className={`btn btn-phone ${calling ? "btn-phone-active" : ""}`}
onClick={() => setCalling(a => !a)}
>
{calling ? <i className="i-phone-hangup" /> : <i className="i-mdi-phone" />}
</button>
</div>
</>
);
};
export default Basics;最终的通话界面如下:
根据连接状态更新 UI
现在 App 已经具备加入频道界面和通话界面,但两个界面之间无法切换。
我们需要使用 useIsConnected 获取用户的连接状态,并且根据连接状态更新 App 界面:
- 在加入频道界面点击加入频道后,如果用户连接成功,App 显示通话界面。
- 在通话界面点击退出通话后,如果连接成功断开,App 显示加入频道界面。
export const Basics = () => {
const [calling, setCalling] = useState(false);
const isConnected = useIsConnected(); // 存储用户的连接状态
const [appId, setAppId] = useState("");
const [channel, setChannel] = useState("");
const [token, setToken] = useState("");
useJoin({appid: appId, channel: channel, token: token ? token : null}, calling);
const [micOn, setMic] = useState(true);
const [cameraOn, setCamera] = useState(true);
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
const { localCameraTrack } = useLocalCameraTrack(cameraOn);
usePublish([localMicrophoneTrack, localCameraTrack]);
const remoteUsers = useRemoteUsers();
return (
<>
<div className="room">
{isConnected ? (
<div className="user-list">
<div className="user">
<LocalUser
audioTrack={localMicrophoneTrack}
cameraOn={cameraOn}
micOn={micOn}
videoTrack={localCameraTrack}
cover="https://www.agora.io/en/wp-content/uploads/2022/10/3d-spatial-audio-icon.svg"
>
<samp className="user-name">You</samp>
</LocalUser>
</div>
{remoteUsers.map((user) => (
<div className="user" key={user.uid}>
<RemoteUser cover="https://www.agora.io/en/wp-content/uploads/2022/10/3d-spatial-audio-icon.svg" user={user}>
<samp className="user-name">{user.uid}</samp>
</RemoteUser>
</div>
))}
</div>
) : (
<div className="join-room">
<img alt="agora-logo" className="logo" src={agoraLogo} />
<input
onChange={e => setAppId(e.target.value)}
placeholder="<Your App ID>"
value={appId}
/>
<input
onChange={e => setChannel(e.target.value)}
placeholder="<Your channel Name>"
value={channel}
/>
<input
onChange={e => setToken(e.target.value)}
placeholder="<Your token>"
value={token}
/>
<button
className={`join-channel ${!appId || !channel ? "disabled" : ""}`}
disabled={!appId || !channel}
onClick={() => setCalling(true)}
>
<span>Join Channel</span>
</button>
</div>
)}
</div>
{isConnected && (
<div className="control">
<div className="left-control">
<button className="btn" onClick={() => setMic(a => !a)}>
<i className={`i-microphone ${!micOn ? "off" : ""}`} />
</button>
<button className="btn" onClick={() => setCamera(a => !a)}>
<i className={`i-camera ${!cameraOn ? "off" : ""}`} />
</button>
</div>
<button
className={`btn btn-phone ${calling ? "btn-phone-active" : ""}`}
onClick={() => setCalling(a => !a)}
>
{calling ? <i className="i-phone-hangup" /> : <i className="i-mdi-phone" />}
</button>
</div>
)}
</>
);
};
export default Basics;离开频道
当用户点击离开频道按钮、关闭浏览器窗口或刷新浏览器标签页时,由于触发了 React 组件的销毁,useJoin 会执行离开频道的操作。你不需要额外调用 API。
后续步骤
在测试或生产环境中,为保证通信安全,声网推荐从服务器中获取 Token,详情请参考使用 Token 鉴权。
参考信息
示例项目
声网在 GitHub 上提供一个开源的示例项目供你参考,包括 React SDK 提供的每个组件和 Hook 以及部分进阶功能的效果展示。
集成 SDK 的其他方法
除了通过 npm 集成 React SDK,你也可以在 HTML 文件中添加如下代码,使用 CDN 方法获取 SDK:
<!-- 必须按照以下顺序依次引入 -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- 如果以上依赖库都已经通过 npm 集成,只需要添加这一行 -->
<script src="https://download.agora.io/sdk/release/agora-rtc-react.2.5.1.js"></script>