实现纯语音互动
- Android
更新时间不可用
了解如何快速接入实时互动 RTC,完成环境准备、参数配置、示例运行和核心流程验证。
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- 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.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 implementation 'cn.shengwang.rtc:voice-sdk:x.y.z' // 对于 4.6.0 之前的版本 // x.y.z 替换为具体的 SDK 版本号,如:4.5.2 implementation 'io.agora.rtc:voice-sdk:x.y.z' }
-
在下载页面下载最新版本的 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 相关的类
Java import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; 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.READ_PHONE_STATE, // 读取电话状态权限 Manifest.permission.BLUETOOTH_CONNECT // 蓝牙连接权限 }; } else { return new String[]{ Manifest.permission.RECORD_AUDIO, }; } } 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;定义 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);加入频道并发布音频流
调用 joinChannel [2/2] 加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置频道场景为
BROADCASTING(直播场景) 并设置用户角色设置为BROADCASTER(主播) 或AUDIENCE(观众)。 - 将
publishMicrophoneTrack设置为true,发布麦克风采集的音频。 - 将
autoSubscribeAudio设置为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.autoSubscribeAudio = true;
// 使用临时 Token 和频道名加入频道,uid 为 0 表示引擎内部随机生成用户名
// 成功后会触发 onJoinChannelSuccess 回调
mRtcEngine.joinChannel(token, channelName, 0, options);实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示如何实现 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) {
super.onUserJoined(uid, elapsed);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "User joined: " + uid, Toast.LENGTH_SHORT).show();
});
}
// 远端用户或主播离开当前频道回调
@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);
}
}结束音频互动
按照以下步骤结束音频互动:
-
调用
leaveChannel离开当前频道,释放所有会话相关的资源。 -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。注意
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
destroy后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
- 调用
Java @Override protected void onDestroy() { super.onDestroy(); if (mRtcEngine != null) { // 离开频道 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 鉴权。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- 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。
集成 SDK
为了减小集成 SDK 后的 App 体积,声网推荐你集成音频 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。可通过发版说明获取最新版本号 pod 'ShengwangAudio_iOS', 'x.y.z' # 对于 4.6.0 之前的版本 # x.y.z 请填写具体的 SDK 版本号,如 4.5.2。可通过发版说明获取最新版本号 pod 'AgoraAudio_iOS', '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/ShengwangAudio_iOS.git // 对于 4.6.0 之前的版本 https://github.com/AgoraIO/AgoraAudio_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 文件中的内容:
实现步骤
下图展示了使用声网 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)加入频道并发布音频流
调用 joinChannelByToken[2/4] 方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
let options = AgoraRtcChannelMediaOptions()
// 设置用户角色为主播
options.clientRoleType = .broadcaster
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true
// 自动订阅所有音频流
options.autoSubscribeAudio = true
// 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
// uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调
agoraKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示了如何实现 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) {
}开始音频互动
当视图加载完成后,在 viewDidLoad 中调用一系列方法加入频道,开始音频互动。
override func viewDidLoad() {
super.viewDidLoad()
// 当加载视图后,你可以进行其他其他设置
// 当调用声网 API 时,以下函数会被调用
initializeAgoraEngine()
joinChannel()
}结束音频互动
-
调用
leaveChannel方法离开频道,与会话相关的资源也会被释放。Swift 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 鉴权。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理 CocoaPods 常见问题?
- 如何处理频道相关常见问题?
- 如何判断一个通话是语音通话还是视频通话?
- 如何处理无声问题?
- 为什么部分 iOS 版本 App 锁屏或切后台后音视频采集无效?
相关文档
本文介绍如何集成声网实时互动 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。 |
进入 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.5.2。可通过发版说明获取最新版本号 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 库。如果你手动集成 RTC SDK 且同时集成了 RTM SDK,为避免冲突,请手动删除版本较低的 aosl.xcframework 库。4.6.0 RTC SDK aosl.xcframework 库版本为 1.3.0。你可以通过查看 aosl.xcframework 文件的属性来得知库的版本信息。
实现步骤
下图展示了使用声网 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)加入频道并发布音频流
调用 joinChannelByToken[2/4] 方法、填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并设置用户角色。
let options = AgoraRtcChannelMediaOptions()
// 设置频道场景为直播
options.channelProfile = .liveBroadcasting
// 设置用户角色为主播
// 如果要将用户角色设置为观众,则修改下一行代码为 options.clientRoleType = .audience
options.clientRoleType = .broadcaster
// 发布麦克风采集的音频
options.publishMicrophoneTrack = true
// 自动订阅所有音频流
options.autoSubscribeAudio = true
// 使用临时 Token 加入频道,在这里传入你的项目的 Token 和频道名
// uid 为 0 表示由引擎内部随机生成; 成功后会触发 didJoinChannel 回调
agoraKit.joinChannel(byToken: <#Your Token#>, channelId: <#Your Channel Name#>, uid: 0, mediaOptions: options)实现常用回调
根据使用场景,定义你所需的回调。以下示例代码展示了如何实现 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)")
}开始纯语音互动
当视图加载完成后,在 viewDidLoad 中调用一系列方法加入频道,开始音视频互动。
override func viewDidLoad() {
super.viewDidLoad()
// 当加载视图后,你可以进行其他设置
// 当调用声网 API 时,以下函数会被调用
joinChannel()
}结束纯语音互动
-
调用
leaveChannel方法离开频道,与会话相关的资源也会被释放。Swift agoraKit.leaveChannel(nil) -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。Swift AgoraRtcEngineKit.destroy()警告
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用该方法后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
调试 App
参考以下步骤来测试你的 App:
- 将 macOS 设备连接至计算机。
- 点击 Build 来运行你的项目,需等待几秒至 App 安装完成。
- 允许 App 访问设备的麦克风权限。
- 使用第二台 macOS 设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:双方可以听到对方的声音。
后续步骤
本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理 CocoaPods 常见问题?
- 如何处理频道相关常见问题?
- 编译 Xcode 项目时遇到 “无法打开 framework” 的弹窗警告怎么办?
- 如何判断一个通话是语音通话还是视频通话?
- 如何设置日志文件?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。
前提条件
-
Windows 或 macOS 计算机,需满足以下要求:
- 下载满足声网 Web SDK 兼容性的浏览器。声网强烈推荐使用最新稳定版 Google Chrome 浏览器。
- 具备物理音视频采集设备。
- 可连接到互联网。如果你的网络环境部署了防火墙,请参考应对防火墙限制以正常使用声网服务。
- 搭载 2.2 GHz Intel 第二代 i3/i5/i7 处理器或同等性能的其他处理器。
-
有效的声网账户和声网项目,请参考开通 RTC 服务,在声网控制台注册、登录并创建声网项目,然后获取项目的 App ID 和 临时 Token。
-
安装 Node.js 18 或更高版本。
信息
有些框架模板可能需要更高版本的 Node.js 才能工作,如果你的包管理器发出警告,请升级你的 Node.js 版本。
创建 Web 项目
创建一个名为 agora_web_quickstart 的文件夹。一个 Web 客户端项目至少需包含以下文件:
index.html: 用于设计 Web 应用的用户界面。basicVoiceCall.js: 通过AgoraRTCClient实现具体应用逻辑的代码。package.json: 安装并管理项目依赖。你可以通过命令行进入agora_web_quickstart目录并运行npm init命令来创建package.json文件。
实现步骤
下文介绍通过声网 RTC SDK 在你的 Web 应用中实现语音通话的详细步骤。
1. 集成 SDK
参考以下步骤通过 npm 将声网 Web SDK 集成到你的项目中:
-
在
package.json文件的dependencies字段中添加agora-rtc-sdk-ng及版本号:JSON { "name": "agora_web_quickstart", "version": "1.0.0", "description": "", "main": "basicVoiceCall.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "agora-rtc-sdk-ng": "latest" }, "author": "", "license": "ISC" } -
将以下代码复制到
basicVoiceCall.js文件中,在你的项目中导入AgoraRTC模块。JavaScript import AgoraRTC from "agora-rtc-sdk-ng"
2. 实现用户界面
将以下代码复制到 index.html 实现客户端用户界面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web SDK Voice 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 Voice Quickstart</h2>
<div class="row">
<div>
<button type="button" id="join">JOIN</button>
<button type="button" id="leave">LEAVE</button>
</div>
</div>
</body>
</html>3. 实现纯语音互动逻辑
参考以下步骤实现纯语音互动的逻辑:
- 调用
createClient方法创建AgoraRTCClient对象。 - 调用
join方法加入一个 RTC 频道,你需要在该方法中传入 App ID、用户 ID、Token 和频道名。 - 先调用
createMicrophoneAudioTrack通过麦克风采集的音频创建本地音频轨道对象,然后调用publish方法,将这些本地音频轨道对象当作参数即可将音频发布到频道中。 - 当一个远端用户加入频道并发布音频轨道时:
- 监听 client.on("user-published") 事件。当 SDK 触发该事件时,在这个事件回调函数的参数中你可以获取远端用户
AgoraRTCRemoteUser对象 。 - 调用
subscribe方法订阅远端用户AgoraRTCRemoteUser对象,获取远端用户的远端音频轨道RemoteAudioTrack对象。 - 调用
play方法播放远端音频轨道。
- 监听 client.on("user-published") 事件。当 SDK 触发该事件时,在这个事件回调函数的参数中你可以获取远端用户
下图展示了实现音频互动的 API 调用流程。注意图中的方法是对不同的对象调用的。
将以下代码复制到 basicVoiceCall.js 文件中,注意将 appId 和 token 参数替换为你自己的 App ID 和临时 Token。
import AgoraRTC from "agora-rtc-sdk-ng";
let rtc = {
localAudioTrack: null,
client: null
};
let options = {
// Pass your App ID here.
appId: "Your App ID",
// Set the channel name.
channel: "test",
// Pass your temp token here.
token: "Your temp token",
// Set the user ID.
uid: 123456,
};
async function startBasicCall() {
// Create an AgoraRTCClient object.
rtc.client = AgoraRTC.createClient({mode: "rtc", codec: "vp8"});
// Listen for the "user-published" event, from which you can get an AgoraRTCRemoteUser object.
rtc.client.on("user-published", async (user, mediaType) => {
// Subscribe to the remote user when the SDK triggers the "user-published" event
await rtc.client.subscribe(user, mediaType);
console.log("subscribe success");
// If the remote user publishes an audio track.
if (mediaType === "audio") {
// Get the RemoteAudioTrack object in the AgoraRTCRemoteUser object.
const remoteAudioTrack = user.audioTrack;
// Play the remote audio track.
remoteAudioTrack.play();
}
});
// Listen for the "user-unpublished" event
rtc.client.on("user-unpublished", async (user) => {
// Unsubscribe from the tracks of the remote user.
await rtc.client.unsubscribe(user);
});
window.onload = function () {
document.getElementById("join").onclick = async function () {
// Join an RTC channel.
await rtc.client.join(options.appId, options.channel, options.token, options.uid);
// Create a local audio track from the audio sampled by a microphone.
rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
// Publish the local audio tracks to the RTC channel.
await rtc.client.publish([rtc.localAudioTrack]);
console.log("publish success!");
}
document.getElementById("leave").onclick = async function () {
// Destroy the local audio track.
rtc.localAudioTrack.close();
// Leave the channel.
await rtc.client.leave();
}
}
}
startBasicCall();调试 App
本文使用 webpack 打包项目,使用 webpack-dev-server 运行项目。参考以下步骤来测试你的 App:
-
在
package.json的dependencies中添加webpack-cli和webpack-dev-server字段中,在scripts字段中添加build和start:dev字段。JSON { "name": "agora_web_quickstart", "version": "1.0.0", "description": "", "main": "basicVoiceCall.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:JavaScript const path = require("path"); module.exports = { entry: "./basicVoiceCall.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "./dist"), }, devServer: { compress: true, port: 9000, }, }; -
运行下列命令安装依赖:
Shell npm install -
运行下列命令通过 webpack 编译项目:
Shell # Use webpack to package the project npm run build -
通过 webpack-dev-server 运行项目:
Shell npm run start:dev你的浏览器会自动打开以下页面:
点击 JOIN 加入频道。你还可以邀请朋友克隆 Gitee 示例项目 或 Github 示例项目 到本地。在浏览器中打开 src/index.html 文件,并输入相同的 App ID、频道名称和临时 Token。你的朋友加入频道后,你们可以听到彼此的声音。
信息
- 在本地服务器(localhost)运行 Web 应用仅作为测试用途。部署生产环境时,请确保使用 HTTPS 协议。
- 由于浏览器的安全策略对除 127.0.0.1 以外的 HTTP 地址作了限制,声网 Web SDK 仅支持 HTTPS 协议、
http://localhost(http://127.0.0.1) 。请勿使用 HTTP 协议在http://localhost(http://127.0.0.1) 之外访问你的项目。
后续步骤
为保障通信安全,在正式生产环境中,你需要在自己的 App 服务端生成 Token。详见使用 Token 鉴权。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
其它集成方式
使用 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。
常见问题
为什么在本地运行快速开始项目时会报错 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方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- 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。
参考下列步骤来在你的应用中实现实时互动:
创建并初始化 IRtcEngine (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++)
调用 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;
// 设置频道场景为直播场景
option.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
option.clientRoleType = CLIENT_ROLE_BROADCASTER;
// 发布麦克风采集的音频流
option.publishMicrophoneTrack = true;
// 自动订阅所有音频流
option.autoSubscribeAudio = 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++)
根据场景需要,如关闭应用或应用切换至后台时,调用 leaveChannel 离开当前频道。
void CAgoraQuickStartDlg::OnBnClickedBtnLeave()
{
// 离开频道
m_rtcEngine->leaveChannel()
}如果你不再需要互动,调用 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 Explorer 窗口,双击 Form1.cs,打开 Toolbox 窗口,选择 Button 控件,依次添加两个按钮,并将两个按钮拖放至合适位置。
- 将鼠标移至其中一个按钮上,点击鼠标右键,选中 Properties,在打开的 Properties 窗口中修改 Text 属性为 Join,修改 Name 属性为 btnJoin。
- 重复上一个步骤来修改另一个按钮的属性:修改 Text 为 Leave;修改 Name 为 btnLeave。
-
创建频道名输入框
- 打开 Toolbox 窗口,选中 TextBox 控件,然后将其拖拽至合适位置。
- 将鼠标移至添加好的输入框控件上,点击鼠标右键,选中 Properties ,修改其属性 Name 为 txChannelName。
-
保存上述步骤的更改。
-
分别双击 Join 和 Leave 按钮,IDE 会自动关联点击事件处理函数。
实现步骤 (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#)
调用 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.autoSubscribeAudio = true;
var ret = engine_.JoinChannel(APP_TOKEN, txChannelName.Text, 0, options);实现常用回调 (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_.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 按钮运行你的项目,然后等待片刻。
- 在应用的输入框中输入你在声网控制台获取的频道名,并点击 Join 按钮加入频道。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。你的朋友加入频道后,你们可以听见对方。
后续步骤
本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- 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模块中声明网络和设备权限:json5 "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" // 始终需要该权限 } }, ] -
打开 src/main/resources/base/element 中的
string.json文件,添加如下代码,定义所需要的权限。JSON { "name": "Internet_reason", "value": "access internet" }, { "name": "Audio_reason", "value": "access audio" }
集成 SDK
-
在下载页面下载最新版本的鸿蒙音频 SDK,并在本地解压。
-
打开解压文件,将
AgoraRtcSdk.har文件复制到项目 entry -> libs 目录下(libs 文件夹需要手动创建)。 -
在 entry 下的
oh-pacakge.json5文件中添加如下依赖,然后点击 Sync 开始同步。JSON "dependencies": { "@shengwang/rtc-voice":"file:./libs/AgoraRtcSdk.har" }
实现方法
下图展示了使用声网 RTC SDK 实现纯语音互动的基本流程。
下面列出了一段实现纯语音互动基本流程的完整代码以供参考。复制以下代码到 pages/Index.ets 文件中替换原有内容,即可快速体验纯语音互动。
信息
在 appId、token 和 channelName 字段中传入你在控制台获取到的 App ID、临时 Token,以及生成临时 Token 时填入的频道名。
处理权限请求
本小节介绍如何获取设备的录音权限。
-
在 entryablility ->
EntryAbility.ets中的onCreate函数中添加权限申请。启动应用程序时,检查是否已在 App 中授予了实现实时互动所需的权限。
ArkTS // 仅保留录音权限 const permissions: Array<Permissions> = ['ohos.permission.INTERNET', 'ohos.permission.MICROPHONE']; 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}`); }); } }); } } }
导入声网组件
打开 pages/Index.ets 文件,导入声网 SDK 组件。
import {
ChannelMediaOptions,
Constants,
RtcEngine,
RtcEngineConfig,
RtcStats,
} from "@shengwang/rtc-voice"初始化引擎
调用 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);加入频道并发布音频流
调用 joinChannelWithOptions 加入频道。在 options 中进行如下配置:
- 设置频道场景为
BROADCASTING(直播场景) 并设置用户角色设置为BROADCASTER(主播)。 - 将
publishMicrophoneTrack设置为true,发布麦克风采集的音频。 - 将
autoSubscribeAudio和autoSubscribeVideo设置为true,自动订阅所有音频流。
let option:ChannelMediaOptions = new ChannelMediaOptions();
// 自动订阅所有音频流
option.autoSubscribeAudio = 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);实现常用回调
根据使用场景,定义必要的回调。以下示例代码展示如何实现 onJoinChannelSuccess 和 onUserOffline 回调。
config.mEventHandler.onUserJoined = (uid: number, collapse: number) => {
console.info("mEventHandler.onUserJoined: " + uid + " , " + collapse);
};
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();
})结束音频互动
按照以下步骤结束音频互动:
-
调用
leaveChannel离开当前频道,释放所有会话相关的资源。 -
调用
destroy销毁引擎,并释放声网 SDK 中使用的所有资源。注意
- 调用
destroy后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
ArkTS 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 鉴权。
相关信息
本节提供了额外的信息供参考。
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
- 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>
Congratulations! You have started a voice call.<br />
Ask a friend to join and chat
</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 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,
} = 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 }
});加入频道并发布音频流
调用 joinChannel 方法,填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并在 options 参数中设置频道场景、用户角色等信息。
// 使用临时 Token 加入频道
rtcEngine.joinChannel(token, channel, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 自动订阅所有音频流
autoSubscribeAudio: true,
});实现常用回调
调用 registerEventHandler 方法注册以下回调事件,触发事件时使用 console.log 方法提示结果:
onJoinChannelSuccess:成功加入频道回调。onUserJoined:远端用户加入当前频道回调。onUserOffline:远端用户离开当前频道回调。
const EventHandles = {
// 监听本地用户加入频道事件
onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
console.log('成功加入频道:' + channelId);
},
// 监听远端用户加入频道事件
onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
console.log('远端用户 ' + remoteUid + ' 已加入');
},
// 监听用户离开频道事件
onUserOffline: ( { channelId, localUid }, remoteUid, reason ) => {
console.log('远端用户 ' + remoteUid + ' 已离开频道');
},
};
// 注册事件回调
rtcEngine.registerEventHandler(EventHandles);离开频道
根据场景需要,如关闭应用或应用切换至后台时,调用 leaveChannel 离开当前频道。
// 离开频道
rtcEngine.leaveChannel();如果你不再需要互动,调用 release 方法释放引擎资源。
// 取消注册回调
rtcEngine.unregisterEventHandler(EventHandles);
// 销毁引擎
rtcEngine.release();警告
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
测试项目
参考以下步骤测试你的 Electron 项目:
-
确保已经在代码中传入了有效的
appId,channelName和token。详见开通 RTC 服务。 -
在终端中进入项目根目录,运行以下命令:
Shell npm start项目成功运行后,你会看到一个自动弹出的窗口:
-
邀请一位朋友使用第二台设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:双方可以听到对方的声音。
-
你的朋友成功加入后,你们可以听见对方。
后续步骤
本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- Electron 平台常见开发问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
-
已下载 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。若你的项目中已有用户界面可略过此步骤。
实现步骤
本节介绍如何使用声网实时互动 SDK 在你的项目中实现纯语音互动功能。
下图展示了实现纯语音互动的基本流程。
下面列出了一段实现实时纯语音互动基本流程的完整代码以供参考。复制以下代码到 JoinChannelAudio.cs 文件中替换原有内容即可。
信息
在 _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文件,将这个文件重新命名为JoinChannelAudio.cs。后续步骤中的示例代码均指该文件中的代码。 -
将脚本和 Canvas 绑定。在
Assets/Agora-Unity-RTC-SDK/Code/Rtc中,选择JoinChannelAudio.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("Leave");
go.GetComponent<Button>().onClick.AddListener(Leave);
go = GameObject.Find("Join");
go.GetComponent<Button>().onClick.AddListener(Join);
}加入频道并发布音频流
调用 JoinChannel[2/2] 方法加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置频道场景为
CHANNEL_PROFILE_LIVE_BROADCASTING(直播场景) 并设置用户角色设置为BROADCASTER(主播)。 - 将
publishMicrophoneTrack设置为true,发布麦克风采集的音频流。 - 将
autoSubscribeAudio设置为true,自动订阅所有音频流。
public void Join() {
Debug.Log("Joining _channelName");
// 启用音频模块
RtcEngine.EnableAudio();
// 设置频道媒体选项
ChannelMediaOptions options = new ChannelMediaOptions();
// 发布麦克风采集的音频流
options.publishMicrophoneTrack.SetValue(true);
// 自动订阅所有音频流
options.autoSubscribeAudio.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);
}实现常用回调
根据使用场景,定义必要的回调。下列示例代码展示本地用户加入频道、远端用户加入、离开频道的回调。
// 创建用户回调类实例,并设置回调
private void InitEventHandler() {
UserEventHandler handler = new UserEventHandler(this);
RtcEngine.InitEventHandler(handler);
}
// 实现你自己的回调类,可以继承 IRtcEngineEventHandler 接口类实现
internal class UserEventHandler : IRtcEngineEventHandler {
private readonly JoinChannelAudio _audioSample;
internal UserEventHandler(JoinChannelAudio audioSample) {
_audioSample = audioSample;
}
// 本地用户成功加入频道时,会触发该回调
public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed) {
Debug.Log("OnJoinChannelSuccess _channelName");
}
// 远端用户成功加入频道时,会触发该回调
public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed) {
Debug.Log("Remote user joined");
}
// 远端用户离开当前频道时,会触发该回调
public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason) {
}
}开始音频互动
在开始音频互动前,先检查是否已获取设备权限,然后在 Start 中调用一系列方法来初始化引擎、注册事件回调、加入频道,开始音频互动。
-
检查是否已获取设备权限。调用
CheckPermissions方法检查是否已获取实现语音互动所需的权限。C# void Update() { CheckPermissions(); } -
开始语音互动。在
Start方法中初始化引擎并开始实时音频互动。C# void Start() { SetupAudioSDKEngine(); InitEventHandler(); SetupUI(); }
结束音频互动
如果你需要退出频道,调用 LeaveChannel 离开当前频道,调用 DisableAudio 关闭音频模块。
public void Leave() {
Debug.Log("Leaving _channelName");
// 离开频道
RtcEngine.LeaveChannel();
// 关闭音频模块
RtcEngine.DisableAudio();
}如果你需要退出应用或者释放 IRtcEngine 内存,调用 Dispose 方法销毁 IRtcEngine。
注意
- 调用
Dispose后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。 - 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
void OnApplicationQuit()
{
if (RtcEngine != null)
{
Leave();
// 销毁 IRtcEngine
RtcEngine.Dispose();
RtcEngine = null;
}
}测试你的项目
按照以下步骤来测试你的语音互动项目:
- 在声网控制台获取一个临时 Token。请参考开通 RTC 服务获取。
- 在
Assets/Agora-Unity-RTC-SDK/Code/Rtc/JoinChannelAudio.cs中,将你的项目的 App ID、频道名以及临时 Token 分别填入到_appID、_channelName、_token之后。 - 在 Unity 编辑器中,点击播放按钮来运行你的项目,然后点击 Join 按钮加入语音互动。
- 邀请一位朋友通过另一台设备来使用相同的 App ID、Token、频道名加入频道。你的朋友加入频道后,你们可以听见对方。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
在实现功能以前,请按照以下要求准备开发环境:
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
- 一个有效的声网账号以及声网项目。请参考开通 RTC 服务从声网控制台获得 App ID 和临时 Token。
注意
临时 Token 的有效期是 24 小时。Token 过期会导致加入频道失败。
创建项目
根据你选用的 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].request();信息
如果你的目标平台是 iOS 或 macOS,需要在 Info.plist 中添加实时互动所需的麦克风权限声明,key 为 Privacy - Microphone Usage Description,value 填写使用目的,如:for a voice call。
初始化引擎
调用 createAgoraRtcEngine 方法创建一个 RtcEngine 对象,然后调用 initialize 初始化引擎并设置频道场景为 channelProfileLiveBroadcasting(直播场景)。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
// 创建 RtcEngine
_engine = await createAgoraRtcEngine();
// 初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景)
await _engine.initialize(const RtcEngineContext(
appId: appId,
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
));加入频道并发布音频流
调用 joinChannel 加入频道。在 ChannelMediaOptions 中进行如下配置:
- 设置用户角色为
clientRoleBroadcaster(主播)或clientRoleAudience(观众)。 - 将
publishMicrophoneTrack设置为true,发布麦克风采集的音频。 - 将
autoSubscribeAudio设置为true,自动订阅所有音频流。
await _engine.joinChannel(
// 使用临时 Token 和频道名加入频道
token: token,
channelId: channel,
options: const ChannelMediaOptions(
// 自动订阅所有音频流
autoSubscribeAudio: true,
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 设置用户角色为 clientRoleBroadcaster(主播)或 clientRoleAudience(观众)
clientRoleType: ClientRoleType.clientRoleBroadcaster),
// uid 为 0 表示引擎内部随机生成用户名
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;
});
},
),
);开始音频互动
在 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 加入频道,观察测试结果,双方可以听到彼此的声音。
后续步骤
- 本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在互动直播的基础上,通过修改观众端的延时级别为低延时 (
audienceLatencyLevelLowLatency)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 如何解决 Flutter 上 iOS release 包初始化时报 symbol not found 的问题?
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
- 已参考 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创建用户界面
根据纯语音互动的场景需要,为你的项目创建加入频道和离开频道按钮。复制以下代码即可快速创建场景所需的用户界面。
实现步骤
本节介绍如何实现一个纯语音互动 App。
下图展示了使用声网 RTC SDK 实现纯语音互动的基本流程。
下面列出了一段实现纯语音互动基本流程的完整代码以供参考,你可以先复制完整的示例代码到你的项目中,参考调试项目中的步骤快速体验实时音视频互动的基础功能,再按照实现流程了解其中的核心 API 调用。
复制以下代码替换 App.tsx 文件的全部内容,即可快速体验纯语音互动基础功能。
在客户端实现语音通话
本节展示如何使用声网 React Native SDK 为你的 App 添加语音通话功能。
导入声网组件
导入构建 App 所需的声网组件。
// 导入声网 SDK
import {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
IRtcEngine,
RtcConnection,
IRtcEngineEventHandler
} 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; // 本地用户 ID,无需修改获取设备权限
根据你的目标平台选择获得麦克风和摄像头的使用权限的方式:
在 Android 设备上,要获得麦克风和摄像头的使用权限,需要弹出提示框供用户选择。
// 导入获取 Android 设备权限相关组件
import {PermissionsAndroid, Platform} from 'react-native';
const getPermission = async () => {
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
]);
}
};在 Xcode 中,打开 info.plist 文件。在右侧列表中添加如下内容,获取相应的设备权限:
| Key | Type | Value |
|---|---|---|
| Privacy - Microphone Usage Description | String | 使用麦克风的目的,例如:for a call or live interactive streaming。 |
初始化引擎
调用 createAgoraRtcEngine 方法创建一个 RtcEngine 实例,然后调用 initialize 初始化引擎。
agoraEngineRef.current = createAgoraRtcEngine();
const agoraEngine = agoraEngineRef.current;
agoraEngine.initialize({
appId: appId,
});加入频道并发布音频流
调用 joinChannel 方法,填入你在控制台获取的临时 Token,以及获取 Token 时填入的频道名加入频道,并在 options 参数中设置频道场景、用户角色等信息。
if (isHost) {
// 以主播角色加入频道
agoraEngineRef.current?.joinChannel(token, channelName, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为主播
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// 发布麦克风采集的音频
publishMicrophoneTrack: true,
// 自动订阅所有音频流
autoSubscribeAudio: true,
});
} else {
// 以观众角色加入频道
agoraEngineRef.current?.joinChannel(token, channelName, uid, {
// 设置频道场景为直播场景
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
// 设置用户角色为观众
clientRoleType: ClientRoleType.ClientRoleAudience,
// 不发布麦克风采集的音频
publishMicrophoneTrack: false,
// 自动订阅所有音频流
autoSubscribeAudio: 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.current!);
// 销毁引擎
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。
-
-
启动 App,点击按钮加入频道。
-
使用第二台设备,重复以上步骤,在该设备上安装 App,并打开 App 加入频道,观察测试结果:双方可以听到对方的声音。
后续步骤
本文的示例使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
参考信息
示例项目
声网提供了开源的纯语音互动示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
- 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
- 前往下载,下载最新版本的 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 中创建加入和离开频道按钮
-
在 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。你可以根据自己的需求调整按钮位置。
-
-
保存上述步骤的更改。
-
创建 Level Blueprint,并关联已创建的 Widget Blueprint
-
在 Unreal Editor 中,点击 Content Drawer,右击选择 Level 并命名为 agoraLevel。
-
双击打开 agoraLevel,点击 Open Level Blueprint。
-
- 右击在搜索框中输入 Create Widget,选择已创建的 AgoraWidget 按照同样的方式依次创建 Event BeginPlay 和 Add to Viewport,并按照下图进行连接:
- 保存上述步骤的更改,并运行项目。
实现步骤
本小节介绍如何实现一个实时音频互动 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/Project/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(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 文件中添加 SetupSDKEngine 的方法和实现。
注意
在初始化 SDK 前,需确保终端用户已经充分了解并同意相关的隐私政策。
// 在 private: 后添加代码
private:
// 获取安卓权限(仅安卓平台需要)
void CheckAndroidPermission();
// 创建并初始化 IRtcEngine
void SetupSDKEngine();// 在 include 后添加代码
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 文件中的 SetupSDKEngine() 后添加设置 UI 元素的方法和实现。示例代码如下:
private:
// 获取安卓权限
void CheckAndroidPermission();
// 创建并初始化 IRtcEngine
void SetupSDKEngine();
// 设置 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()
{
// 设置频道媒体选项
agora::rtc::ChannelMediaOptions options;
// 自动订阅所有音频流
options.autoSubscribeAudio = 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;// 在 SetupSDKEngine() 后添加如下代码:
// 设置远端主播加入频道后触发的回调
void UAgoraWidget::onUserJoined(agora::rtc::uid_t uid, int elapsed)
{
agora::rtc::RtcConnection connection;
connection.channelId = TCHAR_TO_ANSI(*_channelName);
}
// 设置远端主播离开频道时触发的回调
void UAgoraWidget::onUserOffline(agora::rtc::uid_t uid, agora::rtc::USER_OFFLINE_REASON_TYPE reason)
{
agora::rtc::RtcConnection connection;
connection.channelId = TCHAR_TO_ANSI(*_channelName);
}
// 设置本地用户加入频道时触发的回调
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);
});
}清理所有会话相关的资源
离开频道后,如果你想退出应用或者释放 IRtcEngine 内存,需调用 release 方法销毁 IRtcEngine。在 AgoraWidget.h 和 AgoraWidget.cpp 文件中的 NativeConstruct() 后添加 NativeDestruct() 的方法和实现。
注意
- 该方法为同步调用。需要等待引擎资源释放后才能执行其他操作,因此建议在子线程中调用该方法,避免主线程阻塞。
- 调用
release后,你将无法再使用 SDK 的所有方法和回调。如需再次使用实时音视频互动功能,你必须重新创建一个新的引擎。详见初始化引擎。
void NativeDestruct() override;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 鉴权。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?
相关文档
本文介绍如何集成声网实时互动 SDK,通过少量代码从 0 开始实现一个简单的纯语音互动 App,适用于语音通话场景。 首先,你需要了解以下有关音视频实时互动的基础概念:
- 声网实时互动 SDK:由声网开发的、帮助开发者在 App 中实现实时音视频互动的 SDK。
- 频道:用于传输数据的通道,在同一个频道内的用户可以进行实时互动。
- 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频。
- 观众:可以在频道内订阅音视频,不具备发布音视频权限。
更多概念详见关键概念。
下图展示在 App 中实现纯语音互动的基本工作流程:
- 所有用户调用
joinChannel方法加入频道,并将所有用户角色都设置为主播。 - 加入频道后,所有用户都可以在频道内发布音频流,并订阅对方的音频流。
前提条件
- 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中。
实现步骤
本节介绍如何使用声网音频 SDK 在你的项目中实现语音通话功能。
创建 UMG
为直观地体验语音通话,需根据应用场景创建以下控件:
- 加入频道按钮
- 离开频道按钮
参考以下步骤创建上图所示 UI 界面。如果你的项目中已有用户界面,可进行下一步创建关卡。
-
创建 Widget Blueprint。
- 在 Content Browser 的 Content 文件夹中,右击选择 User Interface > Widget Blueprint 创建 Widget Blueprint,并将其命名为 BP_AudioWidget。
- 双击打开 BP_AudioWidget。此时可以在 Hierarchy 面板中看到 BP_AudioWidget > Canvas Panel。
- 创建视图背景。在 Palette 面板中,选择 Common > Image,将其拖至 Canvas Panel 中,命名为 background。通过拖拽调整至画布大小,在 Details 面板中调整背景颜色。
-
在 Widget Blueprint 中创建加入和离开频道的按钮。
- 创建加入频道按钮。在 Palette 面板中,选择 Common > Button,将其拖至 Canvas Panel 中,重命名为 Btn_JoinChannel,并调整其在画布中的位置和大小:
- Position X:-400
- Position Y:0
- Size X:300
- Size Y:50
- 选择 Common > Text,将其拖至 Btn_JoinChannel 中,并在 Details 面板中将 Text 文本内容修改为 JoinChannel。
- 重复上述步骤创建离开频道按钮,将其命名为 Btn_LeaveChannel,并将 Text 文本内容修改为 LeaveChannel。调整按钮在画布中的位置和大小:
- Position X:100
- Position Y:0
- Size X:300
- Size Y:50
- 创建加入频道按钮。在 Palette 面板中,选择 Common > Button,将其拖至 Canvas Panel 中,重命名为 Btn_JoinChannel,并调整其在画布中的位置和大小:
-
保存上述更改。
创建关卡
- 在 Content Browser 的 Content 文件夹中,右击选择 Level 创建 Level Blueprint,并将其命名为 BasicAudioCallScene。
- 双击 BasicAudioCallScene,点击编辑器上方的 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 Audio Widget | 原生 | 创建用户界面。步骤如下:
|
| 4 | Set Basic Audio Call Widget | 自定义 | 设置用户界面。步骤如下:
|
| 5 | Bind UIEvent | 自定义 | 绑定 UI 事件,用于处理点击 JoinChannel 和 LeaveChannel 按钮后的事件逻辑。 |
| 6 | Add to Viewport | 原生 | 将用户界面添加到视口。 |
| 7 | Check Permission | 自定义 |
|
| 8 | Init Rtc Engine | 自定义 | 创建并初始化 RTC 引擎。 |
| 9 | UnInitRtcEngine | 自定义 | 离开频道并释放资源。 |
*原生节点为蓝图内置的节点,无需额外配置即可直接添加调用。
**自定义节点非蓝图内置,需要在创建自定义函数后才能添加对应节点。
加入频道相关变量
- 创建 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 Audio 启用音频模块。
-
调用 Join Channel 加入频道。
-
在 Make ChannelMediaOptions 中设置以下参数:
- 设置 Publish Microphone Track 为 AGORA TRUE VALUE,发布麦克风采集的音频流。
- 设置 Auto Subscribe Audio 为 AGORA TRUE VALUE,自动订阅所有音频流。
- 勾选 Client Role Type Set Value 并设置 Client Role Type 为 CLIENT_ROLE_BROADCASTER,设置用户角色为主播。
- 勾选 Channel Profile Set Value 并设置 Channel Profile 为 CHANNEL_PROFILE_LIVE_BROADCASTING,设置频道场景为直播场景。
-
创建并实现 OnLeaveChannelClicked 事件回调。当事件触发时,调用 Leave Channel 离开频道。
- 在 Bind UIEvent 函数中,参考下图将 OnJoinChannelClicked 和 OnLeaveChannelClicked 回调函数分别绑定 JoinChannel 和 LeaveChannel 按钮。点击按钮时,会触发对应的事件回调。
实现回调函数
将之前创建的 onJoinChannelSuccess、onLeaveChannel、onUserJoined 和 onUserOffline 回调函数按照以下实现步骤进行配置:
- 本地用户成功加入频道后,触发 onJoinChannelSuccess 回调。
- 本地用户离开频道后,触发 onLeaveChannel 回调。
- 远端用户加入频道时,触发 onUserJoined 回调。
- 远端用户离开频道时,触发 onUserOffline 回调。
离开频道并释放资源
参考下图实现 UnInitRtcEngine 函数。
主要步骤如下:
- 离开频道。
- 取消注册 RTC 事件回调。
- 销毁
IRtcEngine对象,释放声网 SDK 使用的所有资源。
测试你的项目
按照以下步骤来测试你的语音通话项目:
- 在 Load Agora Config 函数中,分别填入你的项目的 App ID、频道名以及临时 Token。
2. 在 Unreal Editor 中,点击
来运行你的项目,然后点击 JoinChannel 加入语音通话。 3. 邀请一位朋友通过另一台设备来使用相同的 App ID、频道名、Token 加入频道。你们可以听见对方。
后续步骤
- 如果你的目标平台是 macOS 或 iOS,则需要在打包时添加实时互动所需的摄像头和麦克风等权限,详见如何为 Unreal Engine 项目添加实时互动所需的权限?
- 在本文示例中,使用了临时 Token 加入频道。在测试或生产环境中,为确保通信安全,声网推荐使用 Token 服务器来生成 Token,详见使用 Token 鉴权。
- 如果你想要实现极速直播场景,可以在实时互动直播的基础上,通过修改观众端的延时级别为低延时 (
AUDIENCE_LATENCY_LEVEL_LOW_LATENCY)实现。详见实现极速直播。
参考信息
示例项目
声网提供了开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
常见问题
- 直播场景下,如何监听远端观众角色用户加入/离开频道的事件?
- 如何处理频道相关常见问题?
- 如何设置日志文件?
- 为什么部分 Android 版本应用锁屏或切后台后采集音视频无效?
- 编译 Xcode 项目时遇到无法打开 framework 的弹窗警告怎么办?