Important: This is documentation for the legacy version of the Vivox Unity SDK. This documentation will be removed after July 2025. Refer to the v16 documentation for the new version of the SDK.

Participant events

The Vivox SDK posts information about individual participants in a channel that is visible to all other participants. This includes the following information:

  • When a user joins a channel
  • When a user leaves a channel
  • When there is an important change in user state, such as whether the user is speaking or typing

Handling participant events is optional. If there is no visualization of user state (for example, displaying who has voice enabled), then the game can ignore these events.

To provide a visualization of user state information, a game must handle the following messages:

  • IChannelSession.Participants.AfterKeyAdded
  • IChannelSession.Participants.BeforeKeyRemoved
  • IChannelSession.Participants.AfterValueUpdated

The following code is an example of how to subscribe to these messages:

private void BindChannelSessionHandlers(bool doBind, IChannelSession channelSession)
{
    //Subscribing to the events
    if (doBind)
    {
        // Participants
        channelSession.Participants.AfterKeyAdded += OnParticipantAdded;
        channelSession.Participants.BeforeKeyRemoved += OnParticipantRemoved;
        channelSession.Participants.AfterValueUpdated += OnParticipantValueUpdated;

        //Messaging
        channelSession.MessageLog.AfterItemAdded += OnChannelMessageReceived;
    }

    //Unsubscribing to the events
    else
    {
        // Participants
        channelSession.Participants.AfterKeyAdded -= OnParticipantAdded;
        channelSession.Participants.BeforeKeyRemoved -= OnParticipantRemoved;
        channelSession.Participants.AfterValueUpdated -= OnParticipantValueUpdated;

        //Messaging
        channelSession.MessageLog.AfterItemAdded -= OnChannelMessageReceived;
    }
}

Monitoring subscribed events

The following sections provide information about monitoring specific events that you are subscribed to.

Note: To distinguish between events that pertain to you from events that pertain to other users, use the Participant.IsSelf query.

IChannelSession.Participants.AfterKeyAdded

private void OnParticipantAdded(object sender, KeyEventArg<string> keyEventArg)
{
    ValidateArgs(new object[] { sender, keyEventArg });

    var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender;
    var participant = source[keyEventArg.Key];
    var username = participant.Account.Name;
    var channel = participant.ParentChannelSession.Key;
    var channelSession = participant.ParentChannelSession;
    //Do what you want with the information
}

private static void ValidateArgs(object[] objs)
{
    foreach (var obj in objs)
    {
        if (obj == null)
            throw new ArgumentNullException(obj.GetType().ToString(), "Specify a non-null/non-empty argument.");
    }
}

IChannelSession.Participants.BeforeKeyRemoved

private void OnParticipantRemoved(object sender, KeyEventArg<string> keyEventArg)
{
    ValidateArgs(new object[] { sender, keyEventArg });

    var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender;
    var participant = source[keyEventArg.Key];
    var username = participant.Account.Name;
    var channel = participant.ParentChannelSession.Key;
    var channelSession = participant.ParentChannelSession;
    uIManager.DeleteUserMuteObjectUI(username);

    if (participant.IsSelf)
    {
        BindChannelSessionHandlers(false, channelSession); //Unsubscribe from events here
        currentChannelID = null;

        var user = client.GetLoginSession(accountId);
        user.DeleteChannelSession(channelSession.Channel);
    }
}

IChannelSession.Participants.AfterValueUpdated

private void OnParticipantValueUpdated(object sender, ValueEventArg<string, IParticipant> valueEventArg)
{
    ValidateArgs(new object[] { sender, valueEventArg }); //see code from earlier in post

    var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender;
    var participant = source[valueEventArg.Key];

    string username = valueEventArg.Value.Account.Name;
    ChannelId channel = valueEventArg.Value.ParentChannelSession.Key;
    string property = valueEventArg.PropertyName;

    switch (property)
    {
        case "LocalMute":
        {
            if (username != accountId.Name) //can't local mute yourself, so don't check for it
            {
                //update their muted image
            }
            break;
        }
        case "SpeechDetected":
        {
            //update speaking indicator image
            break;
        }
        default:
        break;
    }
}