使用 Wwise 插件实现空间音频

  • Unity

更新时间不可用

了解游戏语音在不同平台上的 Wwise 插件实现空间音频方式,包括接入流程、关键配置和平台差异。

声网支持你通过 SDK 或 Wwise 插件实现空间音效,两种方案的选型详见适用场景。本文介绍如何通过声网 Wwise 插件在你的 Unity 项目中实现空间音频,增强游戏体验。在多人在线语音视频聊天场景中,空间音效可以实现多人语音的空间感及后期效果处理,大大增强产品的竞争力。

插件概述

声网提供的 Wwise 插件主要用于数据流传输,可与声网 RTC SDK 结合使用,增强 RTC SDK 使用时的灵活性。

声网插件名称插件类别插件用途
AgoraAudioInputSourceWwise Source 插件将 RTC SDK 采集的本地用户音频数据传输给 Wwise
AgoraReceiveSourceWwise Source 插件将 RTC SDK 接收到的远端用户音频数据传输给 Wwise
AgoraSendEffectWwise Effect 插件将用户音频数据发送给声网服务器
AgoraAudioSessionEffectWwise Effect 插件用于在总线上获取参考信号以进行回声消除
表格内容超出当前宽度,可横向滚动查看更多列。

声网 Wwise 插件当前支持如下架构:

  • Android:arm64-v8a、armeabi-v7a、x86、x86_64
  • iOS
  • macOS
  • Windows:vc160、vc170

前提条件

开始前,请确保你的本地有一个 Unity 项目。相关步骤可以参考 RTC 快速开始。

准备开发环境

下载 Wwise 编辑器

  1. 下载 Audiokinetic Launcher(也被称为 Wwise Launcher)。
  2. 在 Audiokinetic Launcher 中安装 Wwise 编辑器 2023.1.6.8555。

下载 SDK 与插件

声网 Unity 平台 Wwise 解决方案由 Wwise 编辑器插件、RTC Unity SDK 和 Wwise Plugin SDK 共同搭建实现,对各模块的兼容版本号有明确要求。在准备开发环境时,请确保下载并安装指定版本的 SDK 和插件:

注意

声网 Wwise Plugin SDK 目前仅适配 Wwise 插件 2023.3.6.8555 和 RTC SDK 4.3.2.14。如果你有其他版本的适配需求,可以联系技术支持。

导入 SDK

  1. 将下载下来的 RTC SDK 添加到你的 Unity 项目中。
  2. 解压下载后的 Agora-Wwise-Plugin 插件,将解压后的 Agora-Wwise-Plugin 文件夹拷贝到你的 Unity 项目的 Assets 文件夹下。
  3. 解压下载后的 Wwise 编辑器插件,会得到一个 AG_Plugin_FULL 文件。在 Wwise Launcher 中,点击左侧的 Plug-ins,然后点击 Add from directory。选中 AG_Plugin_FULL 进行添加。安装完成后,你会在 Plug-ins 界面的 INSTALLED PLUG-INS 区域内看到安装完成的 AgoraWwiseRTCSDK:

集成 Wwise 插件至 Unity 项目

  1. 在 Wwise Launcher 中,点击左侧的 Unity,你应该能看到你创建的 Unity 项目名称,例如 My Project:

  1. 点击项目名右侧的 Integrate Wwise in Project,然后根据屏幕指引,勾选你想要下载包、部署平台,然后点击 Integrate,开始集成。

    注意

    确保你在该步骤中将 Integration version 设置为 2023.1.6.8555。

集成成功后,根据你勾选的部署平台,你应当在你的 Unity 项目路径下找到如下文件。如果没有找到,可以参考手动拷贝 Wwise 插件文件。

在 Wwise 中配置插件

  1. 在 Wwise 中打开你的 Unity 项目。你可以直接从 Wwise Launcher 中 Unity 项目右侧的 Open in Wwise 按钮打开。

  1. 在 Actor-Mixer Hierarchy 下的任意节点单击右键,选择 New Child > AgoraAudioInputSource,创建一个新的 Sound SFX,用于将本地用户音频数据传输给 Wwise。将其重命名,例如 AudioInputSource。

  1. 点击刚刚创建好的 AudioInputSource,在 Effects 面板上点击 + 按钮,新增 AgoraSendEffect,用于将用户音频数据发送给声网服务器。

  1. 在 Actor-Mixer Hierarchy 下的任意节点单击右键,选择 New Child > AgoraReceiveSource,创建一个新的 SoundSFX,用于将远端用户音频数据传输给 Wwise。这里我们可以命名为 AgoraRecevieSource。

  1. 在 Master-Mixer Hierarchy > Default Work Unit > Master Audio Bus 的 Effects 面板下添加 AgoraAudioSessionEffect,用于将本地用户音频数据传输给 Wwise。

  1. 为刚刚创建的 AgoraInputSource 和 AgoraReceiveSource 分别添加 Play 和 Stop 事件。

所有事件创建完成后,效果如下图:

  1. 将刚才创建的所有 Event,Sound SFX 和 Master Audio Bus 加入到 SoundBank 中,并 Generate SoundBank。

在 Unity 项目中使用插件

初始化设置

你需要在该步骤中初始化 RtcEngine 和 Agora Wwise Plugin,并参考如下代码设置相关的私有参数:

C#
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 之间的音频传输。完整的实现逻辑和示例代码如下:

C#
// 加入频道
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);
}

离开频道

C#
_rtcEngineEx.LeaveChannel();

注意

如果你的游戏逻辑中存在 JoinChannel、LeavelChannel 这种反复的操作,请确保在每次 LeaveChannel 之后,调用 Agora.Rtc.AgoraWwiseWrapper.ClearReceiveOpenID(channelId, remoteUid); 清除掉旧频道中已经过期的远端用户绑定。

销毁资源

C#
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 文件,查找如下关键字:

XML
StaticLib="AgoraWwiseRTCSDKFX"

应该可以在文件内查找到如下两处:

将其中的 StaticLib="AgoraWwiseRTCSDKFX" 修改为:

XML
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 项目中: