实时音视频
  • iOS
  • Android
  • macOS
  • Windows
  • HarmonyOS
  • Linux
  • Web : JavaScript
  • 小程序
  • Flutter
  • Electron
  • Unity3D
  • Cocos2D
  • React Native
  • uni-app
  • 产品简介
  • 快速开始
    • 跑通示例源码
    • 集成 SDK
    • 实现视频通话
  • 下载
  • 基础功能
    • 使用 Token 鉴权
    • 常用视频配置
    • 通话质量监测
    • 房间连接状态说明
    • 混流
    • 使用 CDN 直播
    • 房间实时消息
    • 屏幕共享
    • 基础美颜
  • 进阶功能
  • 最佳实践
  • 常见错误码
  • 服务端 API
  • 客户端 API
  • 常见问题

游戏语音

更新时间:2021-12-04 19:41

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 下载示例源码

请参考 下载示例源码 获取源码。

相关源码请查看 “src/Examples/Others/RangeAudio” 目录下的文件。

3 前提条件

在实现范围语音之前,请确保:

并确保开发环境满足以下要求:

  • 准备一台可以连接到互联网的 Windows 或 macOS 计算机。
  • 推荐使用 56 或以上版本的 Chrome 浏览器,不同浏览器的兼容性说明请参考 8 浏览器兼容性

4 注意事项

使用范围语音功能时请务必关注如下注意事项,以免影响接入。

如果您已经使用 ZEGO Express SDK 的实时音视频功能,需要注意以下事项:

  • 由于范围语音功能模块是基于 ZegoExpressEngine 的推拉流接口功能来实现的,使用时无需关注推拉流的概念。在范围语音场景下,推音频流的概念转变为“开启麦克风”,拉音频流的概念转变为“开启扬声器”。建议您不要在接入范围语音功能的同时再使用 startPublishingStreamstartPlayingStream 接口做推拉流操作,避免效果冲突。
  • 范围语音功能模块中推拉流的相关回调(publisherStateUpdateplayerStateUpdate)不再生效。
  • 范围语音功能模块中调用 ZegoExpressEngine 的 on 接口注册了 roomStreamUpdatestreamExtraInfoUpdate 事件回调后,您接入范围语音功能时请勿调用 ZegoExpressEngine 的 off 接口把所有事件回调注销了。

5 使用步骤

5.1 导入 SDK

Express Web SDK 2.10.0 及以上版本可使用按需引入接口的方式导入 SDK 包。

方式一:全量引入

  1. 执行 npm i zego-express-engine-webrtc 命令安装依赖。

npm 下载包支持 typescript 语言(推荐)。

  1. 在 “index.js” 文件中引入 SDK。
import { ZegoExpressEngine } from 'zego-express-engine-webrtc'

方式二:先引入核心功能包,再按需引入范围语音功能模块。

import { ZegoExpressEngine } from 'zego-express-engine-webrtc/core';
import { RangeAudio } from 'zego-express-engine-webrtc/range-audio';
ZegoExpressEngine.use(RangeAudio);

5.2 创建引擎

1. 创建引擎

创建 ZegoExpressEngine 引擎实例,将申请到的 AppID 传入参数 appID,将接入服务器地址传入参数 server

server 为接入服务器地址,获取方式如下:

  1. 登录 ZEGO 控制台
  2. 在对应项目下单击“配置”。
  3. 弹出基本信息后单击“环境配置”下的“查看”按钮。
  4. 在弹窗中的“集成的 SDK”中选择 “Express” 后,再选择 “Web” 平台便可获取对应的接入服务器地址。

初始化 ZegoExpressEngine 实例 zg 和范围语音功能实例 rangeAudio。

const zg = new ZegoExpressEngine(appID, server);
const rangeAudio = zg.createRangeAudioInstance();

2. 监听范围语音事件回调

如果需要注册回调,开发者可根据实际需要,实现 ZegoRangeAudioEvent 中的某些方法,通过范围语音实例 rangeAudio 可调用 on 接口设置回调。

rangeAudio.on("microphoneStateUpdate", (state, errorCode, extendedData) => {
  if (state === 0) {
    // 关闭麦克风声音
  } else if(state === 1) {
    // 开启麦克风中
  } else if(state === 2) {
    // 打开麦克风发送声音
  }
})

5.3 兼容不允许自动播放声音的浏览器

通过 isAudioContextRunning 接口判断浏览器是否支持自动播放声音,如果 isSupportfalse,可以引导用户点击界面的 DOM 元素来触发点击事件,并在点击事件中调用 resumeAudioContext 接口来启动自动播放。

<button onclick="enableAutoPlay()">Click me</button>
const isSupport = rangeAudio.isAudioContextRunning();

async function enableAutoPlay() {
    // result 标识是否启用成功
    const result = await rangeAudio.resumeAudioContext();
}

5.4 登录房间

1. 获取登录 Token

登录房间需要用于验证身份的 Token,获取方式请参考 用户权限控制。如需快速调试,可使用控制台生成临时 Token。

2. 登录房间

通过 ZegoExpressEngine 实例 zg 调用 loginRoom 接口,传入房间 ID 参数 roomIDtoken 和用户参数 user,根据实际情况传入参数 config,登录房间。

  • 在登录房间之前,请先注册登录房间后需要监听的所有回调。成功登录房间后,即可接收相关的回调。
  • roomIDuserIDuserName 参数的取值都为自定义。
  • roomIDuserID 都必须唯一,建议开发者将 userID 设置为一个有意义的值,可将其与自己的业务账号系统进行关联。
// 登录房间,成功则返回 true
const result = await zg.loginRoom(roomID, token, {userID, userName});

5.5 初始化设置

1. 设置听者自身所在位置和朝向

调用 updateSelfPosition 接口可以添加自身方位,或者在自身方位发生变化时更新自己在世界坐标系中的位置和朝向。

  • 在调用 enableSpeaker 打开扬声器之前如果没有调用该接口设置位置信息,则无法接收除小队以外其他人的声音。
  • 自身坐标系三个轴的坐标值可以通过第三方 3D 引擎的旋转角度换算矩阵得到。
参数名 描述
position 自身在世界坐标系中的坐标,参数是长度为 3 的 number 数组,三个值依次表示前、右、上的坐标值。
axisForward 自身坐标系前轴的单位向量,参数是长度为 3 的 number 数组,三个值依次表示前、右、上的坐标值。
axisRight 自身坐标系右轴的单位向量,参数是长度为 3 的 number 数组,三个值依次表示前、右、上的坐标值。
axisUp 自身坐标系上轴的单位向量,参数是长度为 3 的 number 数组,三个值依次表示前、右、上的坐标值。
const position = [0,0,0];
const axisForward = [1,0,0];
const axisRight = [0,1,0];
const axisUp = [0,0,1];

rangeAudio.updateSelfPosition(position, axisForward, axisRight, axisUp); 

2. (可选)设置音频接收距离的最大范围

调用 setAudioReceiveRange 接口设置听者接收音频距离的最大范围,即以自身为起点,3D 空间中以设置的距离为立体空间。设置该范围后,在开启 3D 音效的情况下,声音将会随距离的增加而衰减,直至超出所设置的范围,则不再有声音。小队内的语音,不会受到该值的限制,也不会有 3D 音效。

如果不设置则表示接收音频无距离限制,可听见房间内所有人的声音。

rangeAudio.setAudioReceiveRange(100);

3. (可选)设置是否开启 3D 音效

调用 enableSpatializer 接口设置 3D 音效,enable 取值为 true 时表示开启 3D 音效,此时房间内非小队成员的音频,会随着发声者离自身的距离和方向的变化而产生空间感的变化,为 false 时表示关闭 3D 音效。(可随时开启或关闭)

该功能只对小队以外的人生效。

// enable 为 true 表示开启,为 false 表示关闭。默认是关闭。
rangeAudio.enableSpatializer(true); 

5.6 添加或更新发声者位置信息

登录房间成功后调用 updateAudioSource 接口来更新发声者位置。

  • userID:为房间内其他发声用户的 ID。
  • position:发声者在世界坐标系中的坐标,参数是长度为 3 的 number 数组,三个值依次表示前、右、上的坐标值。
const userID = "other";
const position = [1,0,0];
rangeAudio.updateAudioSource(userID, position);

5.7 设置是否开启麦克风

登录房间成功后调用 enableMicrophone 接口设置是否开启麦克风,当 enable 取值为 true 时表示开启,取值为 false 时表示关闭。(可随时开启或关闭)

需要通过监听 microphoneStateUpdate 事件回调来获取麦克风更新后的状态。

rangeAudio.on("microphoneStateUpdate", (state, errorCode, extendedData) => {
  if (state === 0) {
    // 关闭麦克风声音
  } else if(state === 1) {
    // 开启麦克风中
  } else if(state === 2) {
    // 已打开麦克风发送声音
  }
})
// enable 为 true 表示开启,为 false 表示关闭。
rangeAudio.enableMicrophone(enable);

5.8 设置是否开启扬声器

登录房间成功后调用 enableSpeaker 接口设置是否开启扬声器,enable 取值为 true 时表示开始拉取和播放音频流,为 “false” 时表示停止拉取和播放音频流。(可随时开启或关闭)

当超过最大拉流数限制(目前为 20 路)时,会优先拉取小队内成员音频流(需设置小队模式),再拉取世界内距离自身范围最近的音频流。

// enable 为 true 表示开启,为 false 表示关闭。
rangeAudio.enableSpeaker(enable);

5.9 (可选)设置小队语音功能

1. 设置队伍 ID

调用 setTeamID 接口可根据需要设置想要加入的小队 ID(可随时变更 ID),设置 ID 后即可直接加入。加入小队后,与同一小队内队员之间的交流不受范围语音和 3D 音效的限制。

// 参数 teamID 传入字符串表示加入对应 teamID 的小队。
rangeAudio.setRangeAudioTeamID("teamID");
// 参数 teamID 不传或者传 undefined 表示退出小队。
rangeAudio.setRangeAudioTeamID();

2. 设置语音模式

调用 setRangeAudioMode 接口设置范围语音模式,mode 参数取值为 0 时表示可以听到所有人的声音,取值为 1 时表示只能听到同一小队内其他成员的声音。

语音模式 参数取值 功能描述
全世界 0 设置该模式后,此用户附近一定范围的人都能接收该用户的语音,但不影响小队内成员互相通话。
仅小队 1 设置该模式后,此用户只能听到与自己同一小队的语音,且不受距离限制。
// 参数 mode 可传 0 或 1。
// 0 为世界模式,可与登录房间内的所有人交流。
// 1 为仅小队模式,只与小队内的队员交流。
rangeAudio.setRangeAudioMode(1);

不同范围语音模式下,发声者声音的可接收情况有所不同。

  • 假设 A 用户的模式为 “全世界”,则 B 用户在不同范围语音模式下的声音可接收情况如下:
是否在同一小队 是否在最大范围内 范围语音模式 A 与 B 是否能相互听到对方的声音
同一小队 全世界(World)
仅小队(Team)
全世界(World)
仅小队(Team)
不同小队 全世界(World)
仅小队(Team)
全世界(World)
仅小队(Team)
  • 假设 A 用户的模式为 “仅小队”,则 B 用户在不同范围语音模式下的声音可接收情况如下:
是否在同一小队 是否在最大范围内 范围语音模式 A 与 B 是否能相互听到对方的声音
同一小队 全世界(World)
仅小队(Team)
全世界(World)
仅小队(Team)
不同小队 全世界(World)
仅小队(Team)
全世界(World)
仅小队(Team)

5.10 退出房间

调用 logoutRoom 接口退出房间,退出后将自动关闭麦克风和扬声器(即无法发送自己的音频,也无法收听别人的声音),并清空发声者信息列表。

zg.logoutRoom(roomID)

6 API参考列表

方法 描述
createRangeAudioInstance 创建范围语音实例对象
on 注册回调事件
isAudioContextRunning 判断 AudioContext 对象是否已启用
resumeAudioContext 重新启用内部的 AudioContext 对象
updateSelfPosition 更新听者的位置和朝向
setAudioReceiveRange 设置音频接收距离的最大范围
enableSpatializer 开关 3D 音效
loginRoom 登录房间
updateAudioSource 添加或更新发声者位置信息
enableMicrophone 开关麦克风
enableSpeaker 开关扬声器
setRangeAudioTeamID 设置小队 ID
setRangeAudioMode 设置范围语音模式
logoutRoom 退出房间

7 常见问题

  1. 收听范围内的流最多支持同时拉多少路?

范围语音最多支持同时拉 20 路流。

为保证语音清晰,附近超过 20 人发声时,只能听到离自己最近的 20 个发声者的声音。如果超过 20 人且距离一样,则按照调用 updateAudioSource 接口时,每个 userID 首次传入的先后顺序而定。

  1. 范围语音的“范围”指的是收听范围还是发声范围?

范围语音的“范围”指的是收听范围。

  1. 小队语音中的成员连麦有 3D 音效吗?

小队中的语音是普通连麦的效果,暂无 3D 音效。

  1. 若本身就在调用推流接口,此时需要使用范围语音会存在冲突吗?

范围语音当前使用主路发送音频,如果客户已经使用主路,则会存在冲突。

8 浏览器兼容性

  • 范围语音的浏览器兼容性请参考 ZEGO Express Web SDK 支持哪些浏览器
  • 3D 音效的浏览器兼容性如下:
    浏览器 兼容性
    Chrome 14 及以上
    Edge 79 及以上
    Firefox 53 及以上
    Opera 15 及以上
    IE 不支持
    Safari 14.1 及以上
    WebView Android 55 及以上
    Firefox for Android 53 及以上
    Opera Android 42 及以上
    Safari on iOS 14.5 及以上
    Samsung Internet 6.0 及以上