空间音效(音视频版本)
更新时间: 2024/09/18 16:26:13
空间音效也称 3D 音效,是通过在音频信号中添加空间信息,使得听众可以感受到声音来自于特定的位置和空间环境。它可以增强音频的真实感和沉浸感,让听众感受到更加真实的声音效果。
此文档为您介绍音视频 SDK 如何实现空间音效,若您集成的是纯音频 SDK,请参考空间音效(纯音频版本)。
功能介绍
空间音效可以将实时语音渲染成具有空间方位的效果。同时,空间音效具有房间混响,距离衰减和范围语音等属性,综合使用相关属性可以提升空间音效的真实感和沉浸感。
例如,在游戏中模拟真实世界的空间音效,玩家可以感知说话者的 3D 空间方位。同时,空间音效可以根据双方距离的远近实现语音音量的衰减,使近处的声音更响亮,远处的声音更低。这样可以让玩家更清晰地感受到游戏中的环境和位置信息,增强游戏的沉浸感和真实感。此外,空间音效还可以应用于虚拟现实和增强现实等领域,让用户更真实地感受虚拟环境中的声音效果。
功能原理
空间音效涉及到音频源和接收者两个对象。在RTC场景下,开启空间音效时,发送端会在语音中包含自身的坐标信息,远端接收该音频信息时,会将其作为音频源。接收者会基于自身坐标、接收到的音频及其位置,将音频渲染到特定方位,然后进行播放。
空间音效利用头部相关转换函数(HRTF)和声波空间卷积模仿自然声波的传播,使其仿佛来自三维空间中的一个点。空间音效通过方向、距离和环境三个关键因素实现空间感的形成。
空间音效的距离衰减和语音范围如下图所示。
注意事项
需要用户佩戴有线耳机以体验空间音效功能,暂不支持蓝牙耳机。
API 调用时序
sequenceDiagram
participant 应用层
participant NERtcSDK
participant 云信服务器
Note over 应用层, 云信服务器: 启用并配置空间音效
rect rgb(191, 223, 255)
应用层->>NERtcSDK: EnableSpatializer
NERtcSDK -->>应用层: return code
应用层->>NERtcSDK: UpdateSpatializerAudioRecvRange
NERtcSDK-->>应用层: return code
应用层->>NERtcSDK: SetSpatializerRenderMode
NERtcSDK-->>应用层: return code
应用层->>NERtcSDK: SetAudioProfile
NERtcSDK-->>应用层: return code
应用层->>NERtcSDK: SetSpatializerRoomProperty
应用层->>NERtcSDK: EnableSpatializerRoomEffects
end
Note over 应用层, 云信服务器: 加入房间
应用层->>NERtcSDK: JoinChannel
NERtcSDK->>云信服务器: JoinChannel
云信服务器->>NERtcSDK: OnJoinChannel
NERtcSDK->>应用层: OnJoinChannel
Note over 应用层, 云信服务器: 添加或更新位置信息
rect rgb(191, 223, 255)
应用层->>NERtcSDK: UpdateSpatializerSelfPosition
NERtcSDK->>云信服务器: Voice data setting & rendering
end
实现方法
1. 启用空间音效
请在引擎初始化之后(IRtcEngine.Initialize
),加入房间(IRtcEngine.JoinChannel
)之前调用 EnableSpatializer
方法以启用音频空间化。
示例代码如下:
// 声明类成员
IRtcEngine rtcEngine = IRtcEngine.GetInstance();
//打开空间音效功能
void Enable3DAudio() {
//需要在执行完`IRtcEngine.Initialize`接口之后调用
rtcEngine.EnableSpatializer(true);
//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
}
2. 设置距离衰减和语音范围
在加入房间前,调用 UpdateSpatializerAudioRecvRange
方法设置空间音效的距离衰减属性和语音范围,该属性可以让声音随着音源和听者之间距离的增加逐渐衰减音量。
- 距离衰减属性需要在加入房间之前设置,在通话过程中无法修改该属性,只有退出房间后才可重新设置。
- 空间音效房间内的本端成员和对端成员需要都开启空间音效(
EnableSpatializer
),本端才能听到对端声音的方位感。 - 通常在 3D 网络游戏开始后,都能获取地图上角色 GameObject 坐标,一般用坐标来计算空间距离,传给
UpdateSpatializerAudioRecvRange
接口。
参数描述如下表所示:
参数 | 描述 |
---|---|
audibleDistance | 监听器能接收到音频的最大距离,用户的声音在该范围内可被听见。在该范围内,声音将会随距离的增加而衰减,直至超出所设置的范围,则不再有声音。 取值范围:[0,1000] ,默认值为 32。 |
conversationalDistance | 监听器不对音频进行衰减的距离,在该距离范围内,扬声器音频保持其原始音量,超出该范围时,声音将会随距离的增加而衰减。默认值为 1。 |
rollOff |
距离衰减模式。一共有三种:
|
示例代码如下:
C#// 设置接收范围和声音衰减模型
void Setup3DAudioRecvRange() {
//需要在`EnableSpatializer`执行成功之后调用。
rtcEngine.UpdateSpatializerAudioRecvRange(50, 1, RtcDistanceRolloffModel.kNERtcDistanceRolloffLinear);
// ...
}
3. 设置渲染模式
在加入房间前,调用 SetSpatializerRenderMode
方法设置渲染模式,通过设置 mode
参数选择不同复杂程度的算法以实现不同的听觉效果。
其中 UpdateSpatializerAudioRecvRange
类型的各字段说明如下表所示。
字段 | 描述 |
---|---|
kNERtcSpatializerRenderStereoPanning | 立体声 PANNing 方法 |
kNERtcSpatializerRenderBinauralLowQuality | 低复杂度双耳渲染方法 |
kNERtcSpatializerRenderBinauralMediumQuality | 中复杂度双耳渲染方法 |
kNERtcSpatializerRenderBinauralHighQuality | 高复杂度双耳渲染方法(推荐) |
kNERtcSpatializerRenderRoomEffectsOnly | 仅房间混响 |
示例代码如下:
C#// 设置空间语音渲染模式
void Setup3DAudioRenderMode() {
//需要在`EnableSpatializer`执行成功之后调用。
rtcEngine.SetSpatializerRenderMode(RtcSpatializerRenderMode.kNERtcSpatializerRenderBinauralHighQuality);
// ...
}
4. 设置音频属性
在加入房间前,调用 SetAudioProfile
方法将音频类型(RtcAudioProfileType
)设置为 NERtcAudioProfileMiddleQualityStereo
或者 kNERtcAudioProfileHighQualityStereo
,并将音频场景(RtcAudioScenarioType
)设置为 kNERtcAudioScenarioMusic
。如果是移动端,音频场景需要设置为kNERtcAudioScenarioChatroom
。
C#// 设置音频属性
void Setup3DAudioProfile() {
//需要在`Initialize`执行成功之后,`JoinChannel`之前调用
#if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
rtcEngine.SetAudioProfile(RtcAudioProfileType.kNERtcAudioProfileMiddleQualityStereo, RtcAudioScenarioType.kNERtcAudioScenarioChatroom);
#else
rtcEngine.SetAudioProfile(RtcAudioProfileType.kNERtcAudioProfileMiddleQualityStereo, RtcAudioScenarioType.kNERtcAudioScenarioMusic);
#endif
// ...
}
5. 设置房间混响属性(可选)
- 调用
SetSpatializerRoomProperty
方法设置roomProperty
参数预设的房间大小,混响时长,混响增益,音色亮度等参数,以调整房间混响效果。
其中 RtcSpatializerRoomProperty
类型的各字段说明如下表所示。
参数 | 类型 | 描述 |
---|---|---|
roomCapacity | RtcSpatializerRoomCapacity | 房间大小,默认值为 kNERtcSpatializerRoomCapacitySmall 。房间大小的枚举值请参见 NERtcSpatializerRoomCapacity |
material | NERtcSpatializerMaterialName | 房间材质,默认值为 kNERtcSpatializerMaterialTransparent 。更多的房间材质请参见 NERtcSpatializerMaterialName |
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. 实现游戏空间音频定位特效
在加入房间后,调用 UpdateSpatializerSelfPosition
方法并设置 info
参数,以更新音源或听者的空间位置信息 RtcSpatializerPositionInfo
,从而实现空间音频定位特效。
- 通常在 3D 网络游戏开始后,都能获取地图上角色
GameObject
相互的坐标,此坐标即调用UpdateSpatializerSelfPosition
方法时需要更新的角色坐标。 - 建议在一定间隔内更新角色位置信息,以保证画面和音频位置同步,推荐更新频率为 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} |
示例代码如下:
C#class Demo : MonoBehaviour {
// player or GameObject
public GameObject selfGameObject;
private void Start()
{
StartCoroutine(UpdateMySelfPosition());
}
//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 RtcSpatializerPositionInfo();
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.UpdateSpatializerSelfPosition(info);
if(result != (int)RtcErrorCode.kNERtcNoError)
{
Debug.Log($"UpdateSpatializerSelfPosition Failed : {result}");
}
}
}
}
private void OnDestroy()
{
Debug.Log("OnDestroy");
StopAllCoroutines();
}
}