SDK 接入|游戏语音之“范围语音”接入实践
语音是线上游戏用户的主要交流方式,大多数用户会通过游戏中的内置语音功能与其他玩家沟通,而一些用户在游戏没有内置语音功能的情况下,通过其他语音软件与玩家沟通。
并且,游戏语音在玩家开黑时承担着至关重要的角色。设想在游戏场景中,我们与队友开黑时进行语音交流:互换位置信息、同步“敌方”状况,又或者通过游戏语音感受到来自“敌方”从边侧的进攻、近大远小的脚步声等,这是游戏语音中范围语音和 3D 音效结合后的效果。
=======
ZEGO 游戏语音
======================
ZEGO Express SDK 的游戏语音模块主要包括范围语音、3D 音效、小队语音等,适用于吃鸡类游戏、元宇宙类场景。
在吃鸡类游戏中,小队语音可提供编队功能,在游戏开始前和开始后都可以更换小队,开发者无需关注流分组以及推拉流的实现,直接实现小队语音功能。
在吃鸡游戏和元宇宙场景中,提供 3D 音效能力,在收听发声者音效时,有方向感距离感,让场景感受更真实。
1
范围语音
房间内的收听者对音频的接收距离有范围限制,若发声者与自己的距离超过该范围,则无法听到声音。为保证语音清晰,附近超过 20 人发声时,只能听到离自己最近的 20 个发声者的声音。
假如设置音频接收距离的最大范围为R,若发声者离收听者的距离为 r,则:
当 r < R 时,表示发声者在正常范围内,收听者可以听到声音;
当 r ≥ R 时,表示发声者超出了最大范围,收听者无法听到声音。
下图仅以范围语音模式为“全世界”时为例,更多不同模式组合关系下的声音可达情况请参考 4.9(可选)设置小队语音功能中的“步骤2”。
2
3D 音效
声音有 3D 空间感且按距离衰减。
3
小队语音
玩家可以选择加入小队,并支持在房间内自由切换“全世界”模式、“仅小队”模式、“隐秘小队”模式。
全世界:玩家可与队友互相通话,同时能与范围内同为全世界模式的玩家互相通话;
仅小队:玩家只能与队友互相通话;
隐秘小队:玩家可与队友互相通话,但只能单向接收范围内全世界模式的玩家的语音。
本篇文章我们将聚焦于范围语音模块,讲解范围语音的接入实践,接下来一起来看下具体实操流程。
范围语音接入技术实践
=======================
1
示例源码下载
请参考 下载示例源码 获取源码。相关源码请查看 “/ZegoExpressExample/Examples/AdvancedAudioProcessing/RangeAudio” 目录下的文件。
2
前提条件
在实现范围语音之前,需要确保:
已在项目中集成 ZEGO Express SDK,实现基本的实时音视频功能,详情请参考 快速开始 - 集成 和 快速开始 - 实现视频通话;
已在 ZEGO 控制台 创建项目,并申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目管理 中的“项目信息”。
3
注意事项
使用范围语音功能时请务必关注如下注意事项,以免影响接入。如果您已经使用 ZEGO Express SDK 的实时音视频功能,需要注意以下事项:
由于范围语音功能模块是基于 ZegoExpressEngine 的推拉流接口功能来实现的,使用时无需关注推拉流的概念。在范围语音场景下,推音频流的概念转变为“开启麦克风”,拉音频流的概念转变为“开启扬声器”。建议您不要在接入范围语音功能的同时再使用 startPublishingStream、startPlayingStream 接口做推拉流操作,避免效果冲突。
范围语音功能模块中推拉流的相关回调(onPublisherStateUpdate 、onPlayerStateUpdate、onPublisherQualityUpdate 和 onPlayerQualityUpdate)不再生效。
4
使用步骤
4.1 创建引擎
调用 createEngine 接口,将申请到到 AppID 和 AppSign 传入参数 “appID” 和 “appSign”,创建引擎单例对象。引擎当前只支持同时创建一个实例,超出后将返回 null。
/** 定义 SDK 引擎对象 */
ZegoExpressEngine engine;
ZegoEngineProfile profile = new ZegoEngineProfile();
/** 请通过官网注册获取,格式为 123456789L */
profile.appID = appID;
/** 64个字符,请通过官网注册获取,格式为"0123456789012345678901234567890123456789012345678901234567890123" */
profile.appSign = appSign;
/** 通用场景接入,请根据实际情况选择合适的场景 */
profile.scenario = ZegoScenario.DEFAULT;
/** 设置app的application 对象 */
profile.application = getApplication();
/** 创建引擎 */
engine = ZegoExpressEngine.createEngine(profile, null);
4.2 创建范围语音模块
调用的 createRangeAudio 方法创建范围语音实例。
ZegoRangeAudio rangAudio = engine.createRangeAudio();
if (rangAudio == null) {
printf("创建范围语音实例模块失败");
}
4.3 监听范围语音事件回调
可以根据需要调用 setEventHandler 接口为麦克风设置事件回调,用于监听麦克风的开启状态 onRangeAudioMicrophoneStateUpdate通知。
// set range audio event handler
rangeAudio.setEventHandler(new IZegoRangeAudioEventHandler() {
@Override
public void onRangeAudioMicrophoneStateUpdate(ZegoRangeAudio rangeAudio, ZegoRangeAudioMicrophoneState state, int errorCode) {
super.onRangeAudioMicrophoneStateUpdate(rangeAudio, state, errorCode);
AppLogger.getInstance().callApi("microphone state update. state: %s, errorCode: %d", state, errorCode);
}
});
4.4 登录房间
传入用户 ID 参数 userID 和 userName 创建 ZegoUser 用户对象后,调用 loginRoom 接口,传入房间 ID 参数 roomID 和用户参数 user,登录房间。
同一个AppID内,需保证 roomID 全局唯一;
同一个AppID内,需保证 userID 全局唯一,建议开发者将其设置成一个有意义的值,可将 userID 与自己业务账号系统进行关联;
userID 与 userName 不能为空,否则会导致登录房间失败。
/** 创建用户 */
ZegoUser user = new ZegoUser("user1");
/** 开始登录房间 */
engine.loginRoom("room1", user);
当用户已成功登录房间后,如果应用异常退出,在重启应用后,开发者需先调用 logoutRoom 接口退出房间,再调用 loginRoom接口重新登录房间。
4.5 初始化设置
4.5.1 设置听者自身所在位置和朝向
开发者可以通过调用 updateSelfPosition 接口,设置听者自身的所在位置和方位,或者在自身方位发生变化时更新自己在世界坐标系中的位置和朝向。
在调用 enableSpeaker 打开扬声器之前如果没有调用该接口设置位置信息,则无法接收除小队以外其他人的声音;
自身坐标系三个轴的坐标值可以通过第三方 3D 引擎的旋转角度换算矩阵得到。
// 自身在世界坐标系中的坐标,顺序是前、右、上。
float[] position = new float[]{100.0, 100.0, 100.0};
// 自身坐标系前朝向的单位向量。
float[] axisForward = new float[]{1.0,0.0,0.0};
// 自身坐标系右朝向的单位向量。
float[] axisRight = new float[]{0.0,1.0,0.0};
// 自身坐标系上朝向的单位向量。
float[] axisUp = new float[]{0.0,0.0,1.0};
rangAudio.updateSelfPosition(position, axisForward, axisRight, axisUp);
4.5.2. (可选)设置音频接收距离的最大范围
调用 setAudioReceiveRange 接口设置听者接收音频距离的最大范围,即以自身为起点,3D 空间中以设置的距离为立体空间。设置该范围后,在开启 3D 音效的情况下,声音将会随距离的增加而衰减,直至超出所设置的范围,则不再有声音。小队内的语音,不会受到该值的限制,也不会有 3D 音效。
如果不设置,则表示只能接收本小队内的成员声音,无法接收小队外的所有声音。
rangAudio.setAudioReceiveRange(1000);
4.5.3(可选)设置是否开启 3D 音效
调用 enableSpatializer 接口设置 3D 音效,enable 取值为 true 时表示开启 3D 音效,此时房间内非小队成员的音频,会随着发声者离自身的距离和方向的变化而产生空间感的变化,为 false 时表示关闭 3D 音效。(可随时开启或关闭)
该功能只对小队以外的人生效。
rangAudio.enableSpatializer(true);
4.6 添加或更新发声者位置信息
登录房间成功后,需要通过调用 updateAudioSource 接口,添加或更新发声者的位置信息。
全世界模式下:需要更新房间内,收听者和所有发声者的位置。隐秘小队模式下:需要更新房间内,所有在音频接收范围内,且为全世界模式的发声者的位置。如果未设置发声者位置,或者发声者超出收听者范围,会出现听不到声音的情况;
这里发声者指的是房间内其他人,收听者指的是自己;
userID:为房间内其他发声用户的 ID;
position:发声者在世界坐标系中的坐标,参数是长度为 3 的 float 数组,三个值依次表示前、右、上的坐标值。
// 用户在世界坐标系中的坐标,顺序是前、右、上。
float[] position = new float[]{100.0, 100.0, 100.0};
// 添加/更新用户位置
rangAudio.updateAudioSource("abc",position);
4.7 设置是否开启麦克风
登录房间成功后调用 enableMicrophone 接口设置是否开启麦克风,当 enable 取值为 true 时表示开启,此时 SDK 将会自动使用主通道推音频流,为 false 时表示关闭。(可随时开启或关闭)
需要通过监听 onRangeAudioMicrophoneStateUpdate 事件回调来获取麦克风更新后的状态。
rangAudio.enableMicrophone(true);
4.8 设置是否开启扬声器
登录房间成功后调用 enableSpeaker 接口设置是否开启扬声器,enable 取值为 true 时表示开启,此时将会自动拉取房间内的音频流,为 false 时表示关闭。(可随时开启或关闭)
当超过最大拉流数限制(目前为 20 路)时,会优先拉取小队内成员音频流(需设置小队模式),再拉取世界内距离自身范围最近的音频流。
rangAudio.enableSpeaker(true);
4.9 (可选)设置小队语音功能
4.9.1 设置队伍 ID
调用 setTeamID 接口可根据需要设置想要加入的小队 ID(可随时变更 ID),设置 ID 后即可直接加入。加入小队后,与同一小队内队员之间的交流不受范围语音和 3D 音效的限制。
rangAudio.setTeamID("123");
4.9.2 设置语音模式
调用 setRangeAudioMode 接口设置范围语音模式(可随时切换模式),mode 参数取值为 ZegoRangeAudioModeWorld 或 ZegoRangeAudioSecretTeam 时表示可以听到所有处于世界模式的人的声音,取值为 ZegoRangeAudioModeTeam 时表示只能听到同一小队内其他成员的声音。
rangeAudio.setRangeAudioMode(ZegoRangeAudioMode.WORLD);
不同范围语音模式下,发声者声音的可接收情况有所不同。
- 假设 A 用户的模式为 “全世界”,则 B 用户在不同范围语音模式下的声音可接收情况如下:
- 假设 A 用户的模式为 “仅小队”,则 B 用户在不同范围语音模式下的声音可接收情况如下:
- 假设 A 用户的模式为 “隐秘小队”,则 B 用户在不同范围语音模式下的声音可接收情况如下:
4.10 销毁范围语音模块
当不再使用范围语音模块时可调用 destroyRangeAudio 接口销毁,释放范围语音模块占用的资源。
engine.destroyRangeAudio(rangAudio);
4.11 退出房间
调用 logoutRoom 接口退出房间,退出后将自动关闭麦克风和扬声器(即无法发送自己的音频,也无法收听别人的声音),并清空发声者信息列表。
// 退出房间``engine.logoutRoom("roomID");
API 参考列表
=====================
方法 |
描述 |
创建引擎 |
|
登录房间 |
|
创建范围语音模块 |
|
设置范围语音回调 |
|
设置语音模式 |
|
设置音频接收范围 |
|
设置小队ID |
|
设置是否开启麦克风 |
|
设置是否开启扬声器 |
|
设置是否开启3D音效 |
|
更新房间内发声者位置 |
|
更新自己的位置 |
总结
===============
在游戏内接入语音可提高玩家互动与协作,提升沉浸式游戏体验,便于玩家信息同步。ZEGO 即构科技可提供高品质、低能耗的游戏解决方案,可应用在1v1、团队开黑、狼人杀、剧本杀等场景中。无感延迟,连麦时延低于 300ms,最高可支持50人同时开麦,支持焦点语音,全球500+ 核心节点,服务覆盖 212 个国家和地区,可兼容各种网络下的用户体验。
以上是关于游戏语音中范围语音的SDK接入介绍,如在接入中遇到问题,可添加小极狗进行咨询!
SDK 接入|游戏语音之“范围语音”接入实践的更多相关文章
- Android 通过调用系统,如接口 谷歌语音、百度语音、科大讯飞语音等语音识别方法对话框
现在app在发展过程中会集成一些语音识别功能,不具有其自己的显影剂一般正在开发的语音识别引擎,所以在大多数情况下,它是选择一个成熟的语音识别引擎SDK集成到他们的app在. 平时,这种整合被分成两个, ...
- 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.6,增加语音消息、语音留言等功能
自从微信出来后,语音消息和语音留言变得非常流行,按下一个键说话,比打字要方便多了.GG在V3.6版本增加了对语音消息和语音留言(或称为离线语音消息)的支持.这两个功能的实现已经很完整,只是比较遗憾的一 ...
- 与众不同 windows phone (45) - 8.0 语音: TTS, 语音识别, 语音命令
[源码下载] 与众不同 windows phone (45) - 8.0 语音: TTS, 语音识别, 语音命令 作者:webabcd 介绍与众不同 windows phone 8.0 之 语音 TT ...
- arduino 语音音箱 :语音控制、MP3播放、报时、回复温湿度情况
arduino 语音音箱 :语音控制.MP3播放.报时.回复温湿度情况 效果图 线路图 包装后的效果 功能 需要材料 arduino板 MP3播放模块及喇叭 时钟模块 温湿度模块 语音识别模块 面包板 ...
- python接入微博第三方API之2接入用户登录和微博发布
python接入微博第三方API之2接入用户登录和微博发布 # coding=utf-8 import requests import json import MySQLdb from datetim ...
- 在unity3d游戏中添加中文语音控制
最近打算尝试一下OLAMI在游戏中应用的可能性,这里做一下记录. unity官方教程中的几个项目很精简,但看起来很不错,里面有全套的资源.最后我选择了tanks-tutorial来做这个实验. 下载和 ...
- Scut游戏服务器引擎之Unity3d接入
Scut提供Unity3d Sdk包,方便开发人员快速与Scut游戏服务器对接: 先看Unity3d示例如下: 启动Unity3d项目 打开Scutc.svn\SDK\Unity3d\Assets目录 ...
- 使用讯飞SDK,实现文字在线合成语音
private SpeechSynthesizer mTts; private int isSpeaking = 0; mTts= SpeechSynthesizer.createSynthesize ...
- iOS语音识别,语音播报,文字变语音播报,语音变文字
首先使用的是科大讯飞的sdk 1.语音识别部分 AppDelegate.m #import "AppDelegate.h" #import <iflyMSC/iflyMSC. ...
- iOS第三方语音-微信语音
网址链接:http://pr.weixin.qq.com/ 里面包含了微信语音和图像,集成很简单,下载方demo后会有个文档,按照流程来(因为它只提供了真机的.a文件,所以只能用真机哦,不然会报错) ...
随机推荐
- csp-s2022游记
## 10.29### 民间数据:洛谷 $95+85+60+44=284$ infoj $90+40+40+44=214$ **输麻了**### 赛时经历开考前发现前面坐着 Qiuly,好可怕.开 ...
- .NET周报 【5月第1期 2023-05-06】
国内文章 聊一聊 Valgrind 监视非托管内存泄露和崩溃 https://www.cnblogs.com/huangxincheng/p/17374315.html. 只要是程序总会出现各种莫名其 ...
- 一个好用的java图片缩放及质量压缩方法
本文中代码来自:http://blog.csdn.net/liuhuanchao/article/details/50527856由于网站需要对上传的图片进行宽度判断缩放和质量压缩,以提升整体加载速度 ...
- 【Azure 存储服务】使用 AppendBlobClient 对象实现对Blob进行追加内容操作
问题描述 在Azure Blob的官方示例中,都是对文件进行上传到Blob操作,没有实现对已创建的Blob进行追加的操作.如果想要实现对一个文件的多次追加操作,每一次写入的时候,只传入新的内容? 问题 ...
- #AI 1分钟学会,利用AI制作思维导图 (NewBing&X-Mind )
思维导图是一种有效的思考和学习工具,它可以帮助你整理和呈现信息,激发你的创造力和记忆力.但是,传统的思维导图软件往往需要你花费大量的时间和精力来设计和绘制,而且难以修改和分享.有没有一种更简单和智能的 ...
- 2022-04-24:用go语言重写ffmpeg的muxing.c示例。
2022-04-24:用go语言重写ffmpeg的muxing.c示例. 答案2022-04-24: 本程序的大体过程如下: 打开输出文件并写入头部信息. 添加音频和视频流,并为每个流创建 AVCod ...
- 2022-11-20:小团生日收到妈妈送的两个一模一样的数列作为礼物! 他很开心的把玩,不过不小心没拿稳将数列摔坏了! 现在他手上的两个数列分别为A和B,长度分别为n和m。 小团很想再次让这两个数列变
2022-11-20:小团生日收到妈妈送的两个一模一样的数列作为礼物! 他很开心的把玩,不过不小心没拿稳将数列摔坏了! 现在他手上的两个数列分别为A和B,长度分别为n和m. 小团很想再次让这两个数列变 ...
- 2022-06-15:薯队长最近在参加了一个活动,主办方提供了N个礼物以供挑选, 每个礼物有一个价值,范围在0 ~ 10^9之间, 薯队长可以从中挑选k个礼物。 返回:其中价值最接近的两件礼物之间相差
2022-06-15:薯队长最近在参加了一个活动,主办方提供了N个礼物以供挑选, 每个礼物有一个价值,范围在0 ~ 10^9之间, 薯队长可以从中挑选k个礼物. 返回:其中价值最接近的两件礼物之间相差 ...
- 2022-02-22:机器人大冒险。 力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0)。小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动。指令有两种
2022-02-22:机器人大冒险. 力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0).小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动.指令有两种 ...
- vue全家桶进阶之路31:Vue3 数据和方法的双向绑定ref、reactive、toRefs
ref 在 Vue 3 中,你可以使用 setup 函数来定义组件的数据和方法.在 setup 函数中,你可以使用 ref.reactive 和 computed 等 Vue 3 的响应式 API 来 ...