空间音效(纯音频版本)
更新时间: 2024/09/18 16:26:13
空间音效也称 3D 音效,是通过在音频信号中添加空间信息,使得听众可以感受到声音来自于特定的位置和空间环境。它可以增强音频的真实感和沉浸感,让听众感受到更加真实的声音效果。
此文档为您介绍纯音频版本 SDK 如何实现空间音效,若您集成的是音视频 SDK,请参考空间音效(音视频版本)。
功能介绍
空间音效可以将实时语音渲染成具有空间方位的效果。同时,空间音效具有房间混响,距离衰减和范围语音等属性,综合使用相关属性可以提升空间音效的真实感和沉浸感。
例如,在游戏中模拟真实世界的空间音效,玩家可以感知说话者的 3D 空间方位。同时,空间音效可以根据双方距离的远近实现语音音量的衰减,使近处的声音更响亮,远处的声音更低。这样可以让玩家更清晰地感受到游戏中的环境和位置信息,增强游戏的沉浸感和真实感。此外,空间音效还可以应用于虚拟现实和增强现实等领域,让用户更真实地感受虚拟环境中的声音效果。
功能原理
空间音效涉及到音频源和接收者两个对象。在RTC场景下,开启空间音效时,发送端会在语音中包含自身的坐标信息,远端接收该音频信息时,会将其作为音频源。接收者会基于自身坐标、接收到的音频及其位置,将音频渲染到特定方位,然后进行播放。
空间音效利用头部相关转换函数(HRTF)和声波空间卷积模仿自然声波的传播,使其仿佛来自三维空间中的一个点。空间音效通过方向、距离和环境三个关键因素实现空间感的形成。
空间音效的距离衰减和语音范围如下图所示。
注意事项
需要用户佩戴有线耳机以体验空间音效功能,暂不支持蓝牙耳机。
API 调用时序
sequenceDiagram
participant 应用层
participant NERtcSDK
participant 云信服务器
应用层->>NERtcSDK: Initialize 初始化RTC
Note over 应用层, 云信服务器: 启用并配置空间音效
rect rgb(191, 223, 255)
应用层->>NERtcSDK: InitSpatializer 初始化空间音效
应用层->>NERtcSDK: EnableSpatializer 开启空间音效
应用层->>NERtcSDK: SetSpatializerRenderMode 设置音频渲染模式
应用层->>NERtcSDK: SetAudioRecvRange 设置语音范围
应用层->>NERtcSDK: SetAudioProfile 设置音频属性
end
Note over 应用层, 云信服务器: 加入房间
应用层->>NERtcSDK: JoinChannel
NERtcSDK->>云信服务器: JoinChannel
云信服务器->>NERtcSDK: OnJoinChannel
NERtcSDK->>应用层: OnJoinChannel
Note over 应用层, 云信服务器: 添加或更新位置信息
rect rgb(191, 223, 255)
应用层->>NERtcSDK: UpdateSelfPosition
NERtcSDK->>云信服务器: Voice data setting & rendering
end
实现方法
1. 初始化空间音效
在引擎初始化之后,调用 InitSpatializer
方法初始化空间音效。
2. 开启空间音效
在加入房间(JoinChannel)之前调用 EnableSpatializer
方法启用空间音效。
3. 设置距离衰减和语音范围
调用 SetAudioRecvRange
方法设置空间音效的距离衰减属性和语音范围,该属性可以让声音随着音源和听者距离的增加逐渐衰减音量。距离衰减有 2 种模式,分别为指数衰减和线性衰减。当音源和听者距离超过预设阈值时,音量将会衰减到零。
- 距离衰减属性需要在加入房间之前设置,在通话过程中无法修改该属性,只有退出房间后才可重新设置。
- 空间音效房间内的本端成员和对端成员需要都开启空间音效(
EnableSpatializer
),本端才能听到对端声音的方位感。 - 通常在 3D 网络游戏开始后,都能获取地图上角色 GameObject 坐标,一般用坐标来计算空间距离,传给
SetAudioRecvRange
接口。
参数描述如下表所示:
参数 | 描述 |
---|---|
audibleDistance | 监听器能接收到音频的最大距离,用户的声音在该范围内可被听见。在该范围内,声音将会随距离的增加而衰减,直至超出所设置的范围,则不再有声音。 取值范围:[0,1000] ,默认值为 32。 |
conversationalDistance | 监听器不对音频进行衰减的距离,在该距离范围内,扬声器音频保持其原始音量,超出该范围时,声音将会随距离的增加而衰减。默认值为 1。 |
rollOff |
距离衰减模式。一共有三种:
|
3. 设置渲染模式
调用 SetSpatializerRenderMode
方法设置渲染模式,mode
的参数说明如下表所示。
字段 | 描述 |
---|---|
kNERtcSpatializerRenderStereoPanning(0) | 立体声 PANNing 方法 |
kNERtcSpatializerRenderBinauralLowQuality (1) | 低复杂度双耳渲染方法 |
kNERtcSpatializerRenderBinauralMediumQuality (2) | 中复杂度双耳渲染方法 |
kNERtcSpatializerRenderBinauralHighQuality(3) | 高复杂度双耳渲染方法(推荐) |
kNERtcSpatializerRenderRoomEffectsOnly(4) | 仅房间混响 |
4. 设置音频属性
空间音效需要在佩戴有线耳机的情况下才能体验到。在使用空间音效时,需要调用 SetAudioProfile
方法将音频类型(第一个参数)设置为 MIDDLE_QUALITY_STEREO
或者 HIGH_QUALITY_STEREO
,并将音频场景(第二个参数,scenario)设置为 MUSIC
。
5. 设置房间混响属性(可选)
- 调用
SetSpatializerRoomProperty
方法预设的房间大小,混响时间,混响增益,亮度等参数,改变房间混响效果。 方法设置roomProperty
参数预设的房间大小,混响时长,混响增益,音色亮度等参数,以调整房间混响效果。
其中 RtcSpatializerRoomProperty
类型的各字段说明如下表所示。
参数 | 类型 | 描述 |
---|---|---|
roomCapacity | RtcSpatializerRoomCapacity | 房间大小,默认值为 kNERtcSpatializerRoomCapacitySmall 。房间大小的枚举值请参见 RtcSpatializerRoomCapacity |
material | RtcSpatializerMaterialName | 房间材质,默认值为 kNERtcSpatializerMaterialTransparent 。更多的房间材质请参见 RtcSpatializerMaterialName |
reflectionScalar | float | 混响反射比例因子,默认值为 1.0 |
reverbGain | float | 混响增益比例因子,默认值为 1.0 |
reverbTime | float | 混响时间比例因子,默认值为 1.0 |
reverbBrightness | float | 混响音色亮度 |
-
调用
EnableSpatializerRoomEffects
方法,设置enable
参数为true
或false
以开启或关闭空间音效的房间混响效果。 -
调用
EnableSpatializer
方法,设置enable
参数为true
或false
以开启或关闭 3D 音效。3D 音效可以让声音有 3D 空间感且按距离衰减。
6. 实现游戏空间音频定位特效
通常,在 3D 网络游戏开始后,都能获取地图上角色 GameObject 相互的坐标,而实现角色之间音频空间方位音效需要调用 UpdateSelfPosition
方法进行设置。
- 通常在 3D 网络游戏开始后,都能获取地图上角色
GameObject
相互的坐标,此坐标即调用UpdateSelfPosition
方法时需要更新的角色坐标。 - 建议在一定间隔内更新角色位置信息,以保证画面和音频位置同步,推荐更新频率为 10 ~ 25次/秒。
参数 | 描述 |
---|---|
speakerPosition | 说话者的位置信息,三个值依次表示X、Y、Z的坐标值。默认值{0,0,0} |
speakerQuaternion | 说话者的旋转信息,通过四元组来表示,数据格式为{w, x, y, z}。默认值{0,0,0,0} |
headPosition | 接收者的位置信息,三个值依次表示X、Y、Z的坐标值。默认值{0,0,0} |
headQuaternion | 接收者的旋转信息,通过四元组来表示,数据格式为{w, x, y, z}。默认值{0,0,0,0} |
示例代码
class Demo : MonoBehaviour {
// player or GameObject
public GameObject selfGameObject;
IRtcEngine rtcEngine = IRtcEngine.GetInstance();
private void Start()
{
StartCoroutine(UpdateMySelfPosition());
}
//打开空间音效功能
private void Enable3DAudio()
{
//需要在执行完`IRtcEngine.Initialize`接口之后调用
rtcEngine.InitSpatializer();
rtcEngine.EnableSpatializer(true);
rtcEngine.UpdateAudioRecvRange(50, 1, RtcDistanceRolloffModel.kNERtcDistanceRolloffLinear);
rtcEngine.SetSpatializerRenderMode(RtcSpatializerRenderMode.kNERtcSpatializerRenderBinauralHighQuality);
//打开游戏模式
string paramters = "{\"sdk.enable.plugin.game.mode\":true}"; //game mode
rtcEngine.SetParameters(paramters);
//audio profile must be stereo,2 channels
#if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
rtcEngine.SetAudioProfile(RtcAudioProfileType.kNERtcAudioProfileMiddleQualityStereo, RtcAudioScenarioType.kNERtcAudioScenarioChatroom);
#else
rtcEngine.SetAudioProfile(RtcAudioProfileType.kNERtcAudioProfileMiddleQualityStereo, RtcAudioScenarioType.kNERtcAudioScenarioMusic);
#endif
}
//update my position in the game world
private IEnumerator UpdateMySelfPosition()
{
while (true)
{
yield return new WaitForSeconds(0.2f);
if (selfGameObject != null)
{
/*headPosition、headQuaternion 是指听者的位置,speakerPosition、speakerQuaternion代表说话者的位置。
*听者和说话者可只同一个人的位置,也可以在不同位置,比如说话者丢出去一个探听器来接收探听器所在区域的范围语音。
*/
var info = new RtcPositionInfo();
info.headPosition = new float[3] { selfGameObject.transform.position.x, selfGameObject.transform.position.y, selfGameObject.transform.position.z };
info.headQuaternion = new float[4] { selfGameObject.transform.rotation.x, selfGameObject.transform.rotation.y, selfGameObject.transform.rotation.z, selfGameObject.transform.rotation.w };
info.speakerPosition = info.headPosition;
info.speakerQuaternion = info.headQuaternion;
int result = rtcEngine.UpdateSelfPosition(info);
if(result != (int)RtcErrorCode.kNERtcNoError)
{
Debug.Log($"UpdateSelfPosition Failed : {result}");
}
}
}
}
private void OnDestroy()
{
Debug.Log("OnDestroy");
StopAllCoroutines();
}
}