1 游戏实时语音性能简介
1.1 游戏实时语音概念解释
- 范畴:收听者接管音频的范畴。
- 方位:指收听者在游戏世界坐标中的地位和朝向,详情可参考 5.5 初始化设置 中的“步骤 1”。
- 收听者:房间内接管音频的用户
- 发声者:房间内发送音频的用户。
1.2 游戏实时语音性能形容
ZEGO Express SDK 从 2.11.0 版本起,新增游戏语音模块,次要包含:范畴语音、3D 音效、小队语音。实用于吃鸡类游戏、元宇宙类场景。
在吃鸡类游戏中,小队语音提供编队性能,在游戏开始前和开始后都能够更换小队,开发者无需关注流分组以及推拉流的实现,间接实现小队语音性能。
在吃鸡游戏和元宇宙场景中,提供 3D 音效能力,在收听发声者音效时,有方向感距离感,让场景感触更实在。
实现游戏中的范畴语音
房间内的收听者对音频的接管间隔有范畴限度,若发声者与本人的间隔超过该范畴,则无奈听到声音。为保障语音清晰,左近超过 20 人发声时,只能听到离本人最近的 20 个发声者的声音。
如果设置音频接管间隔的最大范畴为 R,若发声者离收听者的间隔为 r,则:
a. 当 r < R 时,示意发声者在失常范畴内,收听者能够听到声音。
b. 当 r ≥ R 时,示意发声者超出了最大范畴,收听者无奈听到声音。
下图仅以范畴语音模式为“全世界”时为例,更多不同模式组合关系下的声音可达状况请参考 5.9(可选)设置小队语音性能 中的“步骤 2”。
游戏实时音视频的 3D 音效
声音有 3D 空间感且按间隔衰减。
游戏小队模式语音
玩家能够抉择退出小队,并反对在房间内自在切换“全世界”模式、“仅小队”模式、“隐秘小队”模式。
- 全世界:玩家可与队友相互通话,同时能与范畴内同为全世界模式的玩家相互通话。
- 仅小队:玩家只能与队友相互通话。
- 隐秘小队:玩家可与队友相互通话,但只能单向接管范畴内全世界模式的玩家的语音。
2 游戏范畴语音性能 - 示例源码下载
请参考 下载示例源码 获取源码。
相干源码请查看“/ZegoExpressExample/Examples/AdvancedAudioProcessing/RangeAudio”目录下的文件。
3 游戏范畴语音性能实现的前提条件
在实现范畴语音之前,请确保:
- 已在我的项目中集成 ZEGO Express SDK,实现根本的实时音视频性能,详情请参考 疾速开始 – 集成 和 疾速开始 – 实现视频通话。
- 已在 ZEGO 控制台 创立我的项目,并申请无效的 AppID 和 AppSign,详情请参考 控制台 – 项目管理 中的“我的项目信息”。
4 范畴语音实现的注意事项
应用范畴语音性能时请务必关注如下注意事项,免得影响接入。
如果您曾经应用 ZEGO Express SDK 的实时音视频性能,须要留神以下事项:
- 因为范畴语音功能模块是基于 ZegoExpressEngine 的推拉流接口性能来实现的,应用时无需关注推拉流的概念。在范畴语音场景下,推音频流的概念转变为“开启麦克风”,拉音频流的概念转变为“开启扬声器”。建议您不要在接入范畴语音性能的同时再应用
startPublishingStream
、startPlayingStream
接口做推拉流操作,防止成果抵触。
5 实时音视频 - 范畴语音 SDK 的应用步骤
5.1 范畴语音 SDK 创立引擎
调用 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.GENERAL;
/** 设置 app 的 application 对象 */
profile.application = getApplication();
/** 创立引擎 */
engine = ZegoExpressEngine.createEngine(profile, null);
5.2 游戏语音创立范畴语音模块
调用的 createRangeAudio
办法创立范畴语音实例。
ZegoRangeAudio rangAudio = engine.createRangeAudio();
if (rangAudio == null) {printf("创立范畴语音实例模块失败");
}
5.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);
}
});
5.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
接口从新登录房间。
5.5 初始化设置
1. 设置听者本身所在位置和朝向
开发者能够通过调用 updateSelfPosition
接口,设置听者本身的所在位置和方位,或者在本身方位发生变化时更新本人在世界坐标系中的地位和朝向。
- 在调用
enableSpeaker
关上扬声器之前如果没有调用该接口设置地位信息,则无奈接管除小队以外其他人的声音。 - 本身坐标系三个轴的坐标值能够通过第三方 3D 引擎的旋转角度换算矩阵失去。
参数名 | 形容 |
position | 本身在世界坐标系中的坐标,参数是长度为 3 的 float 数组,三个值顺次示意前、右、上的坐标值。 |
axisForward | 本身坐标系前轴的单位向量,参数是长度为 3 的 float 数组,三个值顺次示意前、右、上的坐标值。 |
axisRight | 本身坐标系右轴的单位向量,参数是长度为 3 的 float 数组,三个值顺次示意前、右、上的坐标值。 |
axisUp | 本身坐标系上轴的单位向量,参数是长度为 3 的 float 数组,三个值顺次示意前、右、上的坐标值。 |
// 本身在世界坐标系中的坐标,程序是前、右、上。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);
2.(可选)设置音频接管间隔的最大范畴
调用 setAudioReceiveRange
接口设置听者接管音频间隔的最大范畴,即以本身为终点,3D 空间中以设置的间隔为平面空间。设置该范畴后,在开启 3D 音效的状况下,声音将会随间隔的减少而衰减,直至超出所设置的范畴,则不再有声音。小队内的语音,不会受到该值的限度,也不会有 3D 音效。
如果不设置,则示意只能接管本小队内的成员声音,无奈接管小队外的所有声音。
rangAudio.setAudioReceiveRange(1000);
3.(可选)设置是否开启 3D 音效
调用 enableSpatializer
接口设置 3D 音效,enable 取值为 true 时示意开启 3D 音效,此时房间内非小队成员的音频,会随着发声者离本身的间隔和方向的变动而产生空间感的变动,为 false 时示意敞开 3D 音效。(可随时开启或敞开)
该性能只对小队以外的人失效。
rangAudio.enableSpatializer(true);
5.6 增加或更新发声者地位信息
登录房间胜利后,须要通过调用 updateAudioSource
接口,增加或更新发声者的地位信息。
- 全世界模式下:须要更新房间内,收听者和所有发声者的地位。隐秘小队模式下:须要更新房间内,所有在音频接管范畴内,且为全世界模式的发声者的地位。如果未设置发声者地位,或者发声者超出收听者范畴,会呈现听不到声音的状况。
- 这里发声者指的是房间内其他人,收听者指的是本人。
- userID:为房间内其余发声用户的 ID。
- position:发声者在世界坐标系中的坐标,参数是长度为 3 的 float 数组,三个值顺次示意前、右、上的坐标值。
// 用户在世界坐标系中的坐标,程序是前、右、上。float[] position = new float[]{100.0, 100.0, 100.0};
// 增加 / 更新用户地位
rangAudio.updateAudioSource("abc",position);
5.7 设置是否开启麦克风
登录房间胜利后调用 enableMicrophone
接口设置是否开启麦克风,当 enable 取值为 true 时示意开启,此时 SDK 将会主动应用主通道推音频流,为 false 时示意敞开。(可随时开启或敞开)
须要通过监听 onRangeAudioMicrophoneStateUpdate
事件回调来获取麦克风更新后的状态。
rangAudio.enableMicrophone(true);
5.8 设置是否开启扬声器
登录房间胜利后调用 enableSpeaker
接口设置是否开启扬声器,enable 取值为 true 时示意开启,此时将会主动拉取房间内的音频流,为 false 时示意敞开。(可随时开启或敞开)
当超过最大拉流数限度(目前为 20 路)时,会优先拉取小队内成员音频流(需设置小队模式),再拉取世界内间隔本身范畴最近的音频流。
rangAudio.enableSpeaker(true);
5.9(可选)设置小队语音性能
1. 设置队伍 ID
调用 setTeamID
接口可依据须要设置想要退出的小队 ID(可随时变更 ID),设置 ID 后即可间接退出。退出小队后,与同一小队内队员之间的交换不受范畴语音和 3D 音效的限度。
rangAudio.setTeamID("123");
2. 设置语音模式
调用 setRangeAudioMode
) 接口设置范畴语音模式(可随时切换模式),mode 参数取值为 ZegoRangeAudioModeWorld 或 ZegoRangeAudioSecretTeam 时示意能够听到所有处于世界模式的人的声音,取值为 ZegoRangeAudioModeTeam 时示意只能听到同一小队内其余成员的声音。
语音模式 | 参数取值 | 性能形容 |
---|---|---|
全世界 | WORLD | 设置该模式后,此用户能与小队成员相互通话,且能与范畴内其余全世界模式的人相互通话。 |
仅小队 | TEAM | 设置该模式后,此用户仅能与小队成员相互通话。 |
隐秘小队 | SECRET_TEAM | 设置该模式后,此用户能与小队成员相互通话,且能单向接管范畴内全世界模式的人的语音。 |
rangeAudio.setRangeAudioMode(ZegoRangeAudioMode.WORLD);
不同范畴语音模式下,发声者声音的可接管状况有所不同。
- 假如 A 用户的模式为“全世界”,则 B 用户在不同范畴语音模式下的声音可接管状况如下:
是否在同一小队 | 是否在最大范畴内 | 范畴语音模式 | A 是否听到 B 的声音 | B 是否听到 A 的声音 |
---|---|---|---|---|
同一小队 | 是 | 全世界(World) | 是 | 是 |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
否 | 全世界(World) | 是 | 是 | |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
不同小队 | 是 | 全世界(World) | 是 | 是 |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 是 | ||
否 | 全世界(World) | 否 | 否 | |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 否 |
- 假如 A 用户的模式为“仅小队”,则 B 用户在不同范畴语音模式下的声音可接管状况如下:
是否在同一小队 | 是否在最大范畴内 | 范畴语音模式 | A 是否听到 B 的声音 | B 是否听到 A 的声音 |
---|---|---|---|---|
同一小队 | 是 | 全世界(World) | 是 | 是 |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
否 | 全世界(World) | 是 | 是 | |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
不同小队 | 是 | 全世界(World) | 否 | 否 |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 否 | ||
否 | 全世界(World) | 否 | 否 | |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 否 |
- 假如 A 用户的模式为“隐秘小队”,则 B 用户在不同范畴语音模式下的声音可接管状况如下:
是否在同一小队 | 是否在最大范畴内 | 范畴语音模式 | A 是否听到 B 的声音 | B 是否听到 A 的声音 |
---|---|---|---|---|
同一小队 | 是 | 全世界(World) | 是 | 是 |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
否 | 全世界(World) | 是 | 是 | |
仅小队(Team) | 是 | 是 | ||
隐秘小队(SecretTeam) | 是 | 是 | ||
不同小队 | 是 | 全世界(World) | 是 | 否 |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 否 | ||
否 | 全世界(World) | 否 | 否 | |
仅小队(Team) | 否 | 否 | ||
隐秘小队(SecretTeam) | 否 | 否 |
5.10 销毁范畴语音模块
当不再应用范畴语音模块时可调用 destroyRangeAudio
接口销毁,开释范畴语音模块占用的资源。
engine.destroyRangeAudio(rangAudio);
5.11 退出房间
调用 logoutRoom
接口退出房间,退出后将主动敞开麦克风和扬声器(即无奈发送本人的音频,也无奈收听他人的声音),并清空发声者信息列表。
// 退出房间
engine.logoutRoom("roomID");
5 获取 范畴语音 更多帮忙
获取本文 实时音视频 - 范畴语音 的开发文档、技术支持,拜访即构文档核心开发文档页,适宜对语音音效要求较高的小游戏,元宇宙类场景。