Vivox Unity SDK 16.0.0 升级指南

注意:如果要从 Vivox Unity 版本 15.1.x 或更低版本进行升级,请遵循本指南。

本指南详细介绍如何升级到 Vivox Unity SDK 版本 16.0.0,并重点讨论两个 SDK 版本之间的差异。

版本 16.0.0 推出了简化的功能,并在以下相关方面也进行了更改:

  • SDK 初始化
  • 登录/注销
  • 屏蔽玩家
  • 连接到频道
  • 频道参与者管理
  • 音频设备管理
    • 设置活动设备
    • 设置设备增益/音量
    • 设备静音

SDK 设置和初始化

using VivoxUnity; 替换为 using Unity.Services.Vivox; 以访问 Vivox API。

VivoxUnity 命名空间不再存在。

此外,客户端(用于初始化 SDK 的原始方式)已不复存在。

使用 Authentication

注意:如果您使用的是 Vivox 开发者门户中的凭据,请跳过此部分并跳转到“Vivox 开发者门户凭据”部分。

如果您使用的是 Unity Authentication 包,请依次调用 await UnityServices.InitializeAsync()await AuthenticationService.Instance.SignInAnonymously()await VivoxService.Instance.InitializeAsync(),如以下示例所示:

async void InitializeAsync()
{
    await UnityServices.InitializeAsync();
    await AuthenticationService.Instance.SignInAnonymouslyAsync();
    await VivoxService.Instance.InitializeAsync();
}

还可以使用 AuthenticationService.Instance 提供的任何其他登录选项。

如果项目使用 Unity Dashboard(Unity 后台)凭据但未使用 AuthenticationService 包,则可以启用测试模式并省略 AuthenticationService 登录调用。要打开测试模式,请在 Unity 编辑器中转到 Project Settings > Services > Vivox 并选中标有 Test Mode 的框。

注意:启用测试模式会在客户端上缓存项目的令牌签名密钥,只能用于测试目的。一旦配置了可以向游戏客户端供应 Vivox 访问令牌的安全服务器,就应关闭测试模式。禁用测试模式将从项目中移除令牌签名密钥。

以下示例显示了未使用 AuthenticationService 包但启用了测试模式的初始化设置:

async void InitializeAsync()
{
    await UnityServices.InitializeAsync();
    await VivoxService.Instance.InitializeAsync();
}

使用 Vivox 开发者门户凭据

如果您有旧版 Vivox 开发者门户凭据,请通过 InitializationOptionsVivoxService.Instance.InitializeAsync 提供这些凭据。这些凭据可以包含用于测试目的的签名密钥。

以下示例显示了使用 Vivox 开发者门户凭据的初始化设置:

async void InitializeAsync()
{
    InitializationOptions options = new InitalizationOptions();
    // _key can be excluded from SetVivoxCredentials if an implementation of IVivoxTokenProvider has been provided to the SDK.
    options.SetVivoxCredentials(_server, _domain, _issuer, _key);
    await UnityServices.InitializeAsync(options);
    await VivoxService.Instance.InitializeAsync();
}

注意:在发布应用程序之前,请从 options.SetVivoxCredentials(...) 调用中移除签名密钥(上述示例中的“_key”)。此处还假设已经预配了能够向游戏客户端供应 Vivox 访问令牌的服务器。

登录生命周期更改

ILoginSession.BeginLogin 已替换为 VivoxService.Instance.LoginAsync(LoginOptions options = null) 用于登录 Vivox 服务。

LoginOptions 包含以下各项的属性:

  • DisplayName
  • 启用文本转语音
  • 加入新频道时禁用自动频道传输交换
  • 缓存登录时要为当前玩家屏蔽(交叉静音)的 PlayerID 列表
  • 设置 SDK 接收参与者更新事件的速率
async void LoginToVivoxAsync(List<string> blockedList, string displayName)
{
    LoginOptions options = new LoginOptions();
    options.DisplayName = displayName;
    options.BlockedUserList = blockedList;
    await VivoxService.Instance.LoginAsync(options);
}

ILoginSession.Logout() 已替换为 VivoxService.Instance.LogoutAsync 用于注销 Vivox 服务。

将任何绑定到 LoginSession.PropertyChanged 事件的逻辑(其 PropertyName 为“State”)和 LoginState.LoggedInLoginState.LoggedOut 都移动到其他函数。拆分 login 和 logout 的逻辑以分别在 VivoxService.Instance.LoggedInVivoxService.Instance.LoggedOut 上触发,如以下示例所示。

void Start()
{
    VivoxService.Instance.LoggedIn += OnUserLoggedIn;
    VivoxService.Instance.LoggedOut += OnUserLoggedOut;
}

void OnDestroy()
{
    //Cleanup events if the GameObject is destroyed to prevent unexpected behavior.
    VivoxService.Instance.LoggedIn -= OnUserLoggedIn;
    VivoxService.Instance.LoggedOut -= OnUserLoggedOut;
}

void OnUserLoggedIn()
{
    Debug.Log("The user has successfully logged in");
    // Other logic such as attempting a default channel join or changing the state of voice UIs to indicate the character is logged in can be done here.
}


void OnUserLoggedOut()
{
    Debug.Log("The user has logged out");
    // The LoggedOut event will fire after a VivoxService.Instance.LogoutAsync call has been completed successfully
    // or after an internet disruption has caused Automatic Connection Recovery to declare the attempted recovery a failure.
}

屏蔽玩家

ILoginSession.SetCrossMutedCommunications 已被 VivoxServince.Instance.BlockPlayerAsync(string playerId)VivoxService.Instance.UnblockPlayerAsync(string playerId) 取代,后两者现在需要 playerId 而不是 AccountId 作为输入。

频道生命周期更改

加入和离开频道

所有与 ChannelSession.BeginConnect 相关的逻辑都已替换为以下方法:

注意:根据频道通信能力,将 ChatCapability 设置为 Text、Audio 或 TextandAudio。

ChannelSession.Disconnect() 已替换为:

ILoginSession.ChannelSessions 功能被替换为 VivoxService.Instance.ActiveChannels

VivoxService.Instance.ActiveChannels 是一个字典,其中所有当前活动频道作为键,所有频道的列表 VivoxParticipants 作为值。

以前在实现中依赖 AudioStateTextState 来确定用户是否已连接到频道。现在已将跟踪这两个属性的状态更改的事件替换为与 VivoxService.Instance.ChannelJoinedVivoxService.Instance.ChannelLeft 相关的函数。

VivoxService.Instance.ChannelJoinedVivoxService.Instance.ChannelLeft 将向绑定到事件的任何回调提供加入或离开的频道的频道名称。

以下代码示例是这些更改的示例:

void BindToChannelActions()
{
    //Connecting/Disconnecting channel actions can be done upon VivoxService.Instance.LoggedIn and LoggedOut events being fired, respectively,
    //for basic lifecycle control
    VivoxService.Instance.ChannelJoined += OnChannelJoined;
    VivoxService.Instance.ChannelLeft += OnChannelLeft;
}

void UnbindChannelActions()
{
    VivoxService.Instance.ChannelJoined -= OnChannelJoined;
    VivoxService.Instance.ChannelLeft -= OnChannelLeft;
}

void OnChannelJoined(string channelName)
{
    //The channel with name channelName has been successfully joined, and any UI updates should be done for it
    //Additionally, if multiple channels are being handled, keeping track of the channelName and knowing which channel is for which purpose should be done
    //on the side of the implementation based on this event.
}

void OnChannelLeft(string channelName)
{
    //The channel with name channelName has been successfully left, and any UI updates should be done for it
    //This also means that the channelName can likely be safely lost, although if the channelName is specific and might be rejoined,
    //it should be held on to by the implementation.
}

频道传输

默认情况下,频道传输(语音进入的频道)切换到最近加入的频道。若要禁用此功能,可在使用该 LoginOptions 对象作为输入调用 VivoxService.Instance.LoginAsync 之前将 LoginOptions.DisableAutomaticChannelTransmissionSwap 设置为 true

可以使用 VivoxService.Instance.SetChannelTransmissionModeAsync(TransmissionMode transmissionMode, string channelName = null) 方法手动更改频道传输模式。

此 API 可以根据该方法的输入,将传输频道设置为特定频道、所有频道或无任何传输频道。

频道参与者管理

VivoxParticipant 已取代 ChannelParticipant。

如果使用了正确的键(频道名称),可以通过从 VivoxService.Instance.ActiveChannels 索引中获取值来访问每个活动频道的 VivoxParticipant 集合。

使用 VivoxService.Instance.ParticipantAddedToChannelVivoxServince.Instance.ParticipantRemovedFromChannel 可以了解何时在频道中添加或移除了 VivoxParticipant。

这些事件将提供相关的 VivoxParticipant 作为绑定到这些事件的任何回调的输入。VivoxParticipant 对象包含参与者的 PlayerId、参与者加入或离开的频道名称以及其他有价值的信息,包括参与者是否为本地玩家或玩家的显示名称。以下示例显示了这些类型的事件:

void BindToParticipantEvents()
{
    //These events can be connected at the same time as the channel events from the previous sections for convenience purposes
    VivoxService.Instance.ParticipantAddedToChannel += OnParticipantAdded;
    VivoxService.Instance.ParticipantRemovedFromChannel += OnParticipantRemoved;
}

void UnbindParticipantEvents()
{
    VivoxService.Instance.ParticipantAddedToChannel -= OnParticipantAdded;
    VivoxService.Instance.ParticipantRemovedFromChannel -=OnParticipantRemoved;
}

void OnParticipantAdded(VivoxParticipant participant)
{
    // Use VivoxParticipant to establish some UI element tied to that specific VivoxParticipant, which can then be used to control things such as muting
    // volume, and blocking, along with UI that can track certain states - such as whether the player is currently muted or is currently speaking.
}


void OnParticipantRemoved(VivoxParticipant participant)
{
    // At this point, any UI created to display information about this VivoxParticipant can be safely disposed of.
}

VivoxParticipant 对象

VivoxParticipant 包含有关参与者当前状态的信息,例如:

  • VivoxParticipant.IsSelf,指明参与者是否代表本地玩家。
  • VivoxParticipant.SpeechDetected,指明参与者的音频能量是否超过了 Vivox SDK 将音频视为语音的阈值。

VivoxParticipant 还包含以下事件:

  • ParticipantMuteStateChanged
  • ParticipantSpeechDetected
  • ParticipantAudioEnergyChanged

这些事件可用于创建功能音量单位 (VU) 计量表或语音指示器。请在每个参与者的单个 UI 级别连接这些事件。

注意:这些事件所属的对象应具有对所表示的参与者的引用,以便轻松更新 UI。

以下示例类是 ChatChannelSample 中的 RosterItem 的简化版本:

public class RosterItem : MonoBehaviour
{
    public VivoxParticipant Participant;
    public Text PlayerNameText;


    public void SetupRosterItem(VivoxParticipant participant)
    {
        Participant = participant;
        PlayerNameText.text = Participant.DisplayName;
        Participant.ParticipantMuteStateChanged += OnMuteStateChanged;
        Participant.ParticipantSpeechDetected += OnSpeechDetected;
    }

    void OnMuteStateChanged()
    {
        if(Participant.IsMuted)
        {
            //Participant has been muted
        }
        else
        {
            //Participant has been unmuted
        }
    }

    void OnSpeechDetected()
    {
        //Participant AudioEnergy has exceeded the value required to be considered speech
    }
}

将频道参与者静音

VivoxParticipant.MutePlayerLocally()VivoxParticipant.UnmutePlayerLocally() 可用于将频道中的特定参与者静音/取消静音。

注意:这些 VivoxParticipant 静音/取消静音 API 不会影响本地玩家。

音频设备管理

设备管理不再通过利用 Client 对象来实现。现在可以进行任何设备调整,例如静音、更改音量或使用 VivoxService.Instance 切换活动设备。

将本地玩家静音

本地玩家静音已更改为使用 VivoxService.Instance.MuteInputDevice()VivoxService.Instance.UnmuteInputDevice() 函数,而不必通过 IAudioDevice 对象上的 API 或将频道传输切换为 none 来实现此目的。这些 API 会将本地用户的输入设备静音或取消静音。

调节输入/输出设备音量

现在可以使用 VivoxService.Instance.SetInputDeviceVolume(int value)VivoxService.Instance.SetOutputDeviceVolume(int value) 来调整设备音量。

更改活动输入/输出设备

可以通过调用 VivoxService.Instance.SetActiveOutputDeviceAsync(VivoxOutputDevice device)VivoxService.Instance.SetActiveInputDeviceAsync(VivoxInputDevice device) 来调整活动输入/输出设备。

可以通过访问属性 VivoxService.Instance.AvailableInputDevicesVivoxService.Instance.AvailableOututDevices 来获取 VivoxInputDevicesVivoxOutputDevices 的集合。

以下示例演示如何使用 Vivox SDK 音频设备 API 来填充输入设备的下拉列表,而该列表可用于更改活动输入设备。

using System.Linq;
using Unity.Services.Vivox;
using UnityEngine;
using UnityEngine.UI;


public class AudioDeviceSettings : MonoBehaviour
{
    public Dropdown InputDeviceDropdown;

    private void Start()
    {
        VivoxService.Instance.AvailableInputDevicesChanged += RefreshInputDeviceList;
        InputDeviceDropdown.onValueChanged.AddListener((i) =>
        {
            InputDeviceValueChanged(i);
        });
    }


    void OnEnable()
    {
        RefreshInputDeviceList();
    }


    void OnDestroy()
    {
        // Unbind all UI actions
        InputDeviceDropdown.onValueChanged.RemoveAllListeners();
        VivoxService.Instance.AvailableInputDevicesChanged -= RefreshInputDeviceList;
    }

    private void RefreshInputDeviceList()
    {
        InputDeviceDropdown.Hide();
        InputDeviceDropdown.ClearOptions();
        InputDeviceDropdown.options.AddRange(VivoxService.Instance.AvailableInputDevices.Select(v => new Dropdown.OptionData() { text = v.DeviceName }));
        InputDeviceDropdown.SetValueWithoutNotify(InputDeviceDropdown.options.FindIndex(option => option.text == VivoxService.Instance.ActiveInputDevice.DeviceName));
        InputDeviceDropdown.RefreshShownValue();
    }

    void InputDeviceValueChanged(int index)
    {
        VivoxService.Instance.SetActiveInputDeviceAsync(VivoxService.Instance.AvailableInputDevices.Where(device => device.DeviceName == InputDeviceDropdown.options[index].text).First());
    }
}

注意:这是 ChatChannelSample 示例中使用的 AudioDeviceSettings 类的简化版本,演示了如何更改活动输入/输出设备、调节输入/输出设备音量以及对设备列表更改做出反应。