使用 Wwise 插件实现空间音频
声网支持你通过 SDK 或 Wwise 插件实现空间音效,两种方案的选型详见适用场景。本文介绍如何通过声网 Wwise 插件在你的 Unity 项目中实现空间音频,增强游戏体验。在多人在线语音视频聊天场景中,空间音效可以实现多人语音的空间感及后期效果处理,大大增强产品的竞争力。
插件概述
声网提供的 Wwise 插件主要用于数据流传输,可与声网 RTC SDK 结合使用,增强 RTC SDK 使用时的灵活性。
声网插件名称 | 插件类别 | 插件用途 |
---|---|---|
AgoraAudioInputSource | Wwise Source 插件 | 将 RTC SDK 采集的本地用户音频数据传输给 Wwise |
AgoraReceiveSource | Wwise Source 插件 | 将 RTC SDK 接收到的远端用户音频数据传输给 Wwise |
AgoraSendEffect | Wwise Effect 插件 | 将用户音频数据发送给声网服务器 |
AgoraAudioSessionEffect | Wwise Effect 插件 | 用于在总线上获取参考信号以进行回声消除 |
声网 Wwise 插件当前支持如下架构:
- Android:arm64-v8a、armeabi-v7a、x86、x86_64
- iOS
- macOS
- Windows:vc160、vc170
前提条件
开始前,请确保你的本地有一个 Unity 项目。相关步骤可以参考 RTC 快速开始。
准备开发环境
下载 Wwise 编辑器
-
下载 Audiokinetic Launcher(也被称为 Wwise Launcher)。
-
在 Audiokinetic Launcher 中安装 Wwise 编辑器 2023.1.6.8555。
下载 SDK 与插件
声网 Unity 平台 Wwise 解决方案由 Wwise 编辑器插件、RTC Unity SDK 和 Wwise Plugin SDK 共同搭建实现,对各模块的兼容版本号有明确要求。在准备开发环境时,请确保下载并安装指定版本的 SDK 和插件:
- 点击下载声网 Wwise 编辑器插件 2023.1.6.8555。该插件兼容 Wwise 编辑器 2023.1.6.8555。
- 下载声网 RTC Unity SDK v4.3.2.14。RTC SDK 在 4.3.2.14 及之后的版本均支持 Wwise 解决方案,你也可以前往实时互动下载页下载最新版本的 Unity SDK。
- 下载 声网 Wwise Plugin SDK 2023.1.6.8555_v4.3.2.14。
声网 Wwise Plugin SDK 目前仅适配 Wwise 插件 2023.3.6.8555 和 RTC SDK 4.3.2.14。如果你有其他版本的适配需求,可以联系技术支持。
导入 SDK
-
将下载下来的 RTC SDK 添加到你的 Unity 项目中。
-
解压下载后的 Agora-Wwise-Plugin 插件,将解压后的 Agora-Wwise-Plugin 文件夹拷贝到你的 Unity 项目的 Assets 文件夹下。
-
解压下载后的 Wwise 编辑器插件,会得到一个 AG_Plugin_FULL 文件。在 Wwise Launcher 中,点击左侧的 Plug-ins,然后点击 Add from directory。选中 AG_Plugin_FULL 进行添加。安装完成后,你会在 Plug-ins 界面的 INSTALLED PLUG-INS 区域内看到安装完成的 AgoraWwiseRTCSDK:
集成 Wwsie 插件至 Unity 项目
-
在 Wwise Launcher 中,点击左侧的 Unity,你应该能看到你创建的 Unity 项目名称,例如 My Project:
-
点击项目名右侧的 Integrate Wwise in Project,然后根据屏幕指引,勾选你想要下载包、部署平台,然后点击 Integrate,开始集成。
注意确保你在该步骤中将 Integration version 设置为 2023.1.6.8555。
集成成功后,根据你勾选的部署平台,你应当在你的 Unity 项目路径下找到如下文件。如果没有找到,可以参考手动拷贝 Wwise 插件文件。
- /Assets/Wwise/API/Runtime/Plugins/Android/arm64-v8a/DSP/libAgoraWwiseRTCSDK.so
- /Assets/Wwise/API/Runtime/Plugins/Android/armeabi-v7a/DSP/libAgoraWwiseRTCSDK.so
- /Assets/Wwise/API/Runtime/Plugins/Android/x86/DSP/libAgoraWwiseRTCSDK.so
- /Assets/Wwise/API/Runtime/Plugins/Android/x86_64/DSP/libAgoraWwiseRTCSDK.so
- /Assets/Wwise/API/Runtime/Plugins/iOS/iphoneos/DSP/AgoraWwiseRTCSDKSourceFactory.h
- /Assets/Wwise/API/Runtime/Plugins/iOS/iphoneos/DSP/libAgoraWwiseRTCSDKSource.a
- /Assets/Wwise/API/Runtime/Plugins/iOS/iphonesimulator/DSP/AgoraWwiseRTCSDKSourceFactory.h
- /Assets/Wwise/API/Runtime/Plugins/iOS/iphonesimulator/DSP/libAgoraWwiseRTCSDKSource.a
- /Assets/Wwise/API/Runtime/Plugins/Mac/DSP/libAgoraWwiseRTCSDK.bundle
- /Wwise/API/Runtime/Plugins/Windows/x86/DSP/AgoraWwiseRTCSDK.dll
- /Assets/Wwise/API/Runtime/Plugins/Windows/x86_64/DSP/AgoraWwiseRTCSDK.dll
在 Wwise 中配置插件
-
在 Wwise 中打开你的 Unity 项目。你可以直接从 Wwise Launcher 中 Unity 项目右侧的 Open in Wwise 按钮打开。
-
在 Actor-Mixer Hierarchy 下的任意节点单击右键,选择 New Child > AgoraAudioInputSource,创建一个新的 Sound SFX,用于将本地用户音频数据传输给 Wwise。将其重命名,例如 AudioInputSource。
-
点击刚刚创建好的 AudioInputSource,在 Effects 面板上点击 + 按钮,新增 AgoraSendEffect,用于将用户音频数据发送给声网服务器。
-
在 Actor-Mixer Hierarchy 下的任意节点单击右键,选择 New Child > AgoraReceiveSource,创建一个新的 SoundSFX,用于将远端用户音频数据传输给 Wwise。这里我们可以命名为 AgoraRecevieSource。
-
在 Master-Mixer Hierarchy > Default Work Unit > Master Audio Bus 的 Effects 面板下添加 AgoraAudioSessionEffect,用于将本地用户音频数据传输给 Wwise。
-
为刚刚创建的 AgoraInputSource 和 AgoraReceiveSource 分别添加 Play 和 Stop 事件。
所有事件创建完成后,效果如下图:
-
将刚才创建的所有 Event,Sound SFX 和 Master Audio Bus 加入到 SoundBank 中,并 Generate SoundBank。
在 Unity 项目中使用插件
初始化设置
你需要在该步骤中初始化 RtcEngine
和 Agora Wwise Plugin,并参考如下代码设置相关的私有参数:
using Agora.Rtc;
private IRtcEngineEx _rtcEngineEx = null;
private int _sendTrackId = 0;
// 初始化 RtcEngine
_rtcEngineEx = RtcEngine.CreateAgoraRtcEngineEx();
RtcEngineContext rtcEngineContext = new RtcEngineContext();
rtcEngineContext.appId = appId;
rtcEngineContext.areaCode = AREA_CODE.AREA_CODE_GLOB;
var nRet = _rtcEngineEx.Initialize(rtcEngineContext);
_rtcEngineEx.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
Debug.Log("RtcEngine Initialize: " + nRet);
_rtcEngineEx.InitEventHandler(new RtcEngineEventHandler());
_rtcEngineEx.EnableAudio();
_rtcEngineEx.DisableVideo();
// 初始化 Agora-Wwise-Plugin
IntPtr nativeHandler = IntPtr.Zero;
_rtcEngineEx.GetNativeHandler(ref nativeHandler);
AgoraWwiseWrapper.InitAgoraWwisePlugin(nativeHandler, ref _sendTrackId);
Debug.Log("_sendTrackId :" + _sendTrackId);
// 设置私参
_rtcEngineEx.SetParameters("{\"che.audio.mute_playout_signal\":true}");
// Audio Profile
_rtcEngineEx.SetParameters("{\"che.audio.custom_payload_type\":122}");
_rtcEngineEx.SetParameters("{\"che.audio.custom_bitrate\":24000}");
_rtcEngineEx.SetParameters("{\"che.audio.bitrate_level\":1}");
_rtcEngineEx.SetParameters("{\"che.audio.force_bluetooth_a2dp\":true}");
_rtcEngineEx.SetParameters("{\"che.audio.opensl.sync_downlink_process\":false}");
// Module Related
_rtcEngineEx.SetParameters("{\"che.audio.use_media_volume_in_headset\":1}");
_rtcEngineEx.SetParameters("{\"che.audio.use_media_volume_in_bluetooth\":1}");
_rtcEngineEx.SetParameters("{\"che.audio.ans.noise_gate\":200}");
_rtcEngineEx.SetAudioScenario(AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_GAME_STREAMING);
#if UNITY_IPHONE
_rtcEngineEx.SetParameters("{\"che.audio.keep.audiosession\":true}");
#endif
_rtcEngineEx.SetParameters("{\"che.audio.ps.mode\":0}");
_rtcEngineEx.SetParameters("{\"che.audio.sf.statNsFastNsSpeechTrigThreshold\":0}");
加入频道并收、发流
调用 RTC SDK 的 JoinChannel
方法加入 RTC 频道,并设置订阅和发布选项。
然后将我们在 Wwise 编辑器中创建的 SoungSFX 绑定到用于发流或者收流的 GameObject
,实现 RTC SDK 和 Wwise 之间的音频传输。完整的实现逻辑和示例代码如下:
// 加入频道
var options = new ChannelMediaOptions();
options.publishCameraTrack.SetValue(true);
options.publishMicrophoneTrack.SetValue(true);
options.autoSubscribeAudio.SetValue(true);
options.autoSubscribeVideo.SetValue(true);
options.publishCustomAudioTrack.SetValue(true);
options.publishCustomAudioTrackId.SetValue(_sendTrackId);
_rtcEngineEx.JoinChannel("", channelId, uint.Parse(userId), options);
// 想要正常发流,必须在场景内创建一个用于发流的 GameObject(比如 3D游戏中常见的小人,或者是一个麦克风都可以)
// 并且在这个 GameObject 上绑定一个组件,在组件内填写如下代码
public void Start()
{
// 这段代码用于在我们当前的 GameObject 添加一个我们在 Wwise 编辑器里创建的 Sound SFX
// 该 Sound SFX 会持续的从 RTC SDK 中传输麦克风音频到 Wwise 中
this.gameObject.AddComponent<AkGameObj>();
AkSoundEngine.PostEvent("Play_AudioInputSource", this.gameObject);
}
private void OnDestroy()
{
AkSoundEngine.PostEvent("Stop_AudioInputSource", this.gameObject);
}
// 当远端用户加入 RTC 频道后,需要在当前场景内创建一个用于收流的 GameObject,并且在这个 GameObject 上绑定一个组件,在组件内填写如下代码
public void Start()
{
// remoteUid: 远端用户的 UID
// channelId: RTC 频道的 ID
this.gameObject.AddComponent<AkGameObj>();
ulong gameObjId = AkSoundEngine.GetAkGameObjectID(this.gameObject);
Agora.Rtc.AgoraWwiseWrapper.SetUidToGameObjectIDMapping(gameObjId, channelId, remoteUid);
AkSoundEngine.PostEvent("Play_AgoraReceiveSource", this.gameObject);
}
// 在远端用户离开房间后,需要销毁 GameObject 并且触发其 OnDestroy 方法
private void OnDestroy()
{
AkSoundEngine.PostEvent("Stop_AgoraReceiveSource", this.gameObject);
Agora.Rtc.AgoraWwiseWrapper.ClearReceiveOpenID(channelId, remoteUid);
}
// 在频道里下麦
public void MuteLocal()
{
var options = new ChannelMediaOptions();
options.publishCameraTrack.SetValue(false);
options.publishMicrophoneTrack.SetValue(false);
options.autoSubscribeAudio.SetValue(true);
options.autoSubscribeVideo.SetValue(true);
options.publishCustomAudioTrack.SetValue(false);
options.publishCustomAudioTrackId.SetValue(_sendTrackId);
_rtcEngineEx.UpdateChannelMediaOptions(options);
}
// 在频道上麦
public void UnmuteLocal()
{
var options = new ChannelMediaOptions();
options.publishCameraTrack.SetValue(true);
options.publishMicrophoneTrack.SetValue(true);
options.autoSubscribeAudio.SetValue(true);
options.autoSubscribeVideo.SetValue(true);
options.publishCustomAudioTrack.SetValue(true);
options.publishCustomAudioTrackId.SetValue(_sendTrackId);
_rtcEngineEx.UpdateChannelMediaOptions(options);
}
离开频道
_rtcEngineEx.LeaveChannel();
如果你的游戏逻辑中存在 JoinChannel
、LeavelChannel
这种反复的操作,请确保在每次 LeaveChannel
之后,调用 Agora.Rtc.AgoraWwiseWrapper.ClearReceiveOpenID(channelId, remoteUid);
清除掉旧频道存在的已经过期的远端用户绑定。
销毁资源
Agora.Rtc.AgoraWwiseWrapper.UninitAgoraWwisePlugin();
_rtcEngineEx.LeaveChannel();
_rtcEngineEx.Dispose();
_rtcEngineEx = null;
请确保在 Agora.Rtc.AgoraWwiseWrapper.UninitAgoraWwisePlugin();
之前,调用了 Agora.Rtc.AgoraWwiseWrapper.ClearReceiveOpenID(channelId, remoteUid);
来清除之前调用 Agora.Rtc.AgoraWwiseWrapper.SetUidToGameObjectIDMapping();
所绑定的 uid
和 channelId
。
参考信息
构建 App 注意事项
导出 iOS 工程时,控制台会报错,提示 AgoraWwiseRTCSDKFX.a
找不到。此时需要打开你生成的 SoundBanks。默认情况下,SoundBanks 文件位于 Wwise 编辑器工程 /GeneratedSoundBanks/iOS
文件夹下。如果你设置了其他路径,请打开对应的目录。然后打开 PluginInfo.xml
文件,查找如下关键字:
StaticLib="AgoraWwiseRTCSDKFX"
应该可以在文件内查找到如下两处:

将其中的 StaticLib="AgoraWwiseRTCSDKFX"
修改为:
StaticLib="AgoraWwiseRTCSDKSource"
修改后如下所示,保存文件:

接着,我们在 Unity Editor 里导出 iOS 工程并用 Xcode 打开之后,可以在 Libraries/Wwise/API/Runtime/Plugins/iOS/iphoneos/DSP
文件下,看到如下三个文件,和 include "AgoraWwiseRTCSDKSourceFactory.h"
这句代码:

至此,iOS 的 App 构建得以顺利完成。
如果在 Xcode 目录下并没有 AkiOSPlugins
文件,请检查 Data/Raw/Audio/GeneratedSoundBanks/iOS/PluginInfo.xml
文件中内容是否为被修改后的内容:

如果发现该文件内的内容又恢复到了 StaticLib="AgoraWwiseRTCSDKFX"
,则说明在构建过程中 SoundBanks 被重新生成了,导致之前的文本修改被重新覆盖。此时可以检查是否在 Unity Editor 里勾选了 Generate SoundBanks at pre-Build step:

手动拷贝 Wwise 插件文件
在集成 Wwise 到 Unity 项目中之后,如果你发现缺失了上文中列出的部分的文件,可以手动将这些文件拷贝进入 Unity 项目中:
源文件 | 拷贝到 Unity 项目目录 |
---|---|
/Wwise2023.1.6.8555/SDK/Android_arm64-v8a /Release/bin/libAgoraWwiseRTCSDK.so | /Assets/Wwise/API/Runtime/Plugins/Android/arm64-v8a /DSP/libAgoraWwiseRTCSDK.so |
/Wwise2023.1.6.8555/SDK/Android_armeabi-v7a /Release/bin/libAgoraWwiseRTCSDK.so | /Assets/Wwise/API/Runtime/Plugins/Android/armeabi-v7a /DSP/libAgoraWwiseRTCSDK.so |
/Wwise2023.1.6.8555/SDK/Android_x86 /Release/bin/libAgoraWwiseRTCSDK.so | /Assets/Wwise/API/Runtime/Plugins/Android/x86 /DSP/libAgoraWwiseRTCSDK.so |
/Wwise2023.1.6.8555/SDK/Android_x86_64 /Release/bin/libAgoraWwiseRTCSDK.so | /Assets/Wwise/API/Runtime/Plugins/Android/x86_64 /DSP/libAgoraWwiseRTCSDK.so |
源文件 | 拷贝到 Unity 项目目录 |
---|---|
/Wwise2023.1.6.8555/SDK/iOS_Xcode1500 /Release-iphoneos/lib/libAgoraWwiseRTCSDKSource.a | /Assets/Wwise/API/Runtime/Plugins/iOS /iphoneos/DSP/libAgoraWwiseRTCSDKSource.a |
/Wwise2023.1.6.8555/SDK/include/AK /Plugin/AgoraWwiseRTCSDKSourceFactory.h | Assets/Wwise/API/Runtime/Plugins/iOS /iphoneos/DSP/AgoraWwiseRTCSDKSourceFactory.h |
/Wwise2023.1.6.8555/SDK/iOS_Xcode1500 /Release-iphonesimulator/lib/libAgoraWwiseRTCSDKSource.a | /Assets/Wwise/API/Runtime/Plugins/iOS /iphonesimulator/DSP/libAgoraWwiseRTCSDKSource.a |
/Wwise2023.1.6.8555/SDK/include/AK /Plugin/AgoraWwiseRTCSDKSourceFactory.h | /Assets/Wwise/API/Runtime/Plugins/iOS /iphonesimulator/DSP/AgoraWwiseRTCSDKSourceFactory.h |
源文件 | 拷贝到 Unity 项目目录 |
---|---|
/Wwise2023.1.6.8555/SDK/Mac_Xcode1500 /Release/bin/libAgoraWwiseRTCSDK.dylib | /Assets/Wwise/API/Runtime/Plugins/Mac /DSP/libAgoraWwiseRTCSDK.bundle |
将文件拷贝过去后需要将文件后缀名从 .dylib
修改为 .bundle
。
源文件 | 拷贝到 Unity 项目目录 |
---|---|
/Wwise2023.1.6.8555/SDK/Win32_vc160 /Release/bin/AgoraWwiseRTCSDK.dll | /Wwise/API/Runtime/Plugins/Windows/x86 /DSP/AgoraWwiseRTCSDK.dll |
/Wwise2023.1.6.8555/SDK/x64_vc160 /Release/bin/AgoraWwiseRTCSDK.dll | /Assets/Wwise/API/Runtime/Plugins/Windows/x86_64 /DSP/AgoraWwiseRTCSDK.dll |