# IChannelSession

> Learn how IChannelSession changed in the upgrade.

Various functions in the VivoxVoiceChat module are replaced by the functionality in [IChannelSession](../../reference-manual/unreal/class_i_channel_session). For code examples and usage notes, see [Join a channel](../channels/join-channel).

The following list provides the name of the function in the VivoxVoiceChat module, the comparable function in VivoxCore, and supplemental information for completing a version switch.

> **Note:**
>
> Most functions related to channel sessions in VivoxCore must be called directly from methods on an IChannelSession object. In the VivoxVoiceChat module, you would typically use a channel name to reference the underlying channel; it is possible in VivoxCore to get the right reference with the channel name by iterating over the ILoginSession.ChannelSessions() for the ChannelId key with the proper name, and then grabbing the TSharedPtr\<IChannelSession> for the IChannelSession. Alternatively, a developer could refactor their integration to instead hold on to the ChannelId where they need it, and then use ILoginSession.GetChannelSession() to obtain the reference.

* `JoinChannel(const FString& ChannelName, const FString& ChannelCredentials, EVoiceChatChannelType ChannelType, const FOnVoiceChatChannelJoinCompleteDelegate& Delegate, TOptional<FVoiceChatChannel3dProperties> Channel3dProperties)` is replaced by `BeginConnect(bool connectAudio, bool connectText, bool switchTransmission, const FString& accessToken, FOnBeginConnectCompletedDelegate theDelegate)`

  * JoinChannel() is the most changed function within IChannelSession, and requires a fundamentally different approach that what is detailed in *Join a channel*.

    1. The developer must create the IChannelSession for the channel they want to connect to, which requires a ChannelId(const FString& issuer, const FString& name, const FString& domain, ChannelType type, Channel3DProperties properties). Set the ChannelType to Positional and change Channel3DProperties to create a custom positional 3D voice channel, as detailed in [Positional channels](../channels/positional-channels).
    2. After creating the ChannelId, you can use ILoginSession.GetChannelSession(const ChannelId \&channelId). This either returns the proper IChannelSession for the ChannelId if it already exists, or creates a new one.
    3. After the IChannelSession has been made, you can join the channel with BeginConnect(bool connectAudio, bool connectText, bool switchTransmission, const FString& accessToken, FOnBeginConnectCompletedDelegate theDelegate) with an accessToken that is either generated with IChannelSession.GetConnectToken(const FString& tokenSigningKey, FTimespan tokenExpirationDuration), which is insecure and must not be used in a production environment, or by properly creating the access token on a server by using best practices from the [Access Token Developer Guide](../../access-token-guide/access-token-guide-toc).

* `LeaveChannel(const FString& ChannelName, const FOnVoiceChatChannelLeaveCompleteDelegate& Delegate)` is replaced by `Disconnect()`

  * LeaveChannel and Disconnect() are very similar. The primary difference is that LeaveChannel requires a reference to a channel name, and Disconnect() must be called on the IChannelSession object to disconnect. You can work around this difference, with ILoginSession.ChannelSessions() returning a TMap of IChannelSessions keyed by their ChannelIds.
  * You can iterate through the IChannelSessions of the proper ILoginSession for the IChannelSession with the ChannelId containing the correct ChannelId::Name(), and then disconnect from that IChannelSession. Alternatively, you can instantiate and use an identical ChannelId with ILoginSession.GetChannelSession(const ChannelId \&channelId) to return the IChannelSession.

* ` OnChannelJoined, FOnVoiceChatChannelJoinedDelegate` is replaced by `EventAfterParticipantAdded`

  * The replacement to the functionality of the FOnVoiceChatChannelJoinedDelegate ties in to the event EventAfterParticipantAdded. Checking if the participant added to the channel session is the local user by checking IParticipant::IsSelf() on the participant in each EventAfterParticipantAdded allows the game to know when you have fully joined the channel. If BeginConnect() succeeds (you are in the Connecting state) and the method bound to FOnBeginConnectCompletedDelegate returns no errors (you are in the Connected state), the local user is not fully considered to be in the channel until they have received their own participant added event, which is received last. This is because after being connected, the channel must process a series of incoming events to build an accurate map of the channel state and its participants.

* `FOnVoiceChatPlayerAddedDelegate` is replaced by `EventAfterParticipantAdded`

  * When a participant is added to a channel, EventAfterParticipantAdded fires on the IChannelSession with the IParticipant that joined.

* `FOnVoiceChatChannelExitedDelegate` is replaced by `EventBeforeParticipantRemoved`

  * Similar to replacing the FOnVoiceChatChannelJoinedDelegate with EventAfterParticipantAdded, you can replace FOnVoiceChatChannelExitedDelegate with the functionality of calling IsSelf() on the participant when the EventBeforeParticipantRemoved fires.

* `FOnVoiceChatPlayerRemovedDelegate` is replaced by `EventBeforeParticipantRemoved`

  * When a participant is added to a channel, EventBeforeParticipantRemoved fires on the IChannelSession with the IParticipant that joined.

* `GetPlayersInChannel(FString ChannelName)` is replaced by `Participants()`

  * `Participants()` can replace `GetPlayersInChannel()`. The main functional difference is that it returns a map of player names to IParticipant objects instead of an array of player names.

  * You can use the following code to generate a key array of every player name in the session:

    ```plaintext
    /* . . . */
    TArray<FString> playersInChannel;
    MyChannelSession.Participants().GenerateKeyArray(&playersInChannel);
    /* . . . */
    ```

* `Set3DPosition(const FString& ChannelName, const FVector& SpeakerPosition, const FVector& ListenerPosition, const FVector& ListenerForwardDirection, const FVector& ListenerUpDirection)` is replaced by `Set3DPosition(const FVector \&speakerPosition, const FVector \&listenerPosition, const FVector \&listenerForwardVector, const FVector \&listenerUpVector)`

  * Set3DPosition() in VivoxCore must be called on the IChannelSession with name ChannelId::Name() instead of passing it in as a parameter.

* `FOnVoiceChatPlayerTalkingUpdatedDelegate` is replaced by `EventAfterParticipantUpdated`

  * FOnVoiceChatPlayerTalkingUpdatedDelegate is replaced by an EventAfterParticipantUpdated, which raises after any participant’s ParticipantProperties change within the IChannelSession.
  * Checking for SpeechDetected() allows the system to know if that participant is transmitting voice. However, by default, VoiceEnergy is prevented from updating unless speech is detected.
  * Checking for VoiceEnergy() allows the system to know how loud the player is being, but requires a change in setup.
  * For more information, see [Create a dynamic voice energy meter](../audio/in-game-audio-control/create-dynamic-voice-energy-meter).

* `OnInvalidChannelCredentials(), FOnChannelJoinFailedDelegate` is replaced by `FOnBeginConnectCompletedDelegate`

  * After you call BeginConnect() to try to connect to the channel, if the channel credentials are invalid or the channel cannot be joined for some reason, FOnBeginConnectCompletedDelegate triggers with a status code other than VxErrorSuccess.
  * Some types of errors, such as invalid arguments, are immediately caught and are returned by BeginConnect(), in which case the delegate method never fires because it stopped before the asynchronous request could be made.
  * If BeginConnect() returns VxErrorSuccess, then the bound delegate is called with any server side errors, such as invalid credentials, or another VxErrorSuccess.
