UE4 and Vivox

Implementing Vivox into your UE4 project.

Nov. 18, 2020, 3 p.m.

So you want a cross-platform and scalable voice chat? Great, let's begin.

 

Prerequisites

  • A Vivox developer account (you need a v5 account so ask for a v5 account via email)
  • A Vivox app
  • A C++ UE4 project (or ability to add C++)
  • Patience

NOTE: Make sure you check this or like I said above email the support for a v5 account.

 

BeginPlay()

Cool once you have your app and credentials then proceed to step 1.

So most of this will be implemented in your GameInstance, GameMode, and PlayerController. If you have better classes to add this to then by all means reach out and let me know.You could also just download the example project by Vivox instead of reading this post if you want to see their implementation.

You can skip the guide and just download the project if you'd like. Get it here.

 

  1. Download the SDK (Unreal Windows SDK) from Vivox. (at the time of writing this the SDK is on version 5.12.0)
  2. Add the plugin to your Plugins folder in your project and then edit your Build.cs file and add the following.
    PublicDependencyModuleNames.AddRange(new string[] { "VivoxCore" });
  3. One quick note before you start writing code, make sure you add your GameInstance as the default one in Edit -> Project Settings.
  4. Go to your GameInstance and add the following. (I didn't add the code directly to the post since it's a few hundred lines - instead, you can get it here.)
    (NOTE: I'm not 100% sure if the muting and audio device code works, I just threw it together)
  5. Now to your PlayerController and GameMode classes.
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/PlayerController.h"
    
    #include "MyPlayerController.generated.h"
    
    UCLASS()
    class VIVOXEXAMPLE_API AMyPlayerController : public APlayerController
    {
        GENERATED_BODY()
    
    public:
        UFUNCTION(Client, Unreliable)
        void ClientJoinVoice(const uint8 TeamNumber, const FString& SessionID);
    };
    
    
    // -------------------------------------------- CPP
    #include "MyPlayerController.h"
    
    #include "MyGameInstance.h"
    
    void AMyPlayerController::ClientJoinVoice_Implementation(const uint8 TeamNumber, const FString& SessionID)
    {
        if (!IsPrimaryPlayer())
        {
            return;
        }
    
        if (IsLocalController())
        {
            if (UMyGameInstance* const GI = GetWorld()->GetGameInstance<UMyGameInstance>())
            {
                GI->JoinVoiceChannels(TeamNumber, SessionID);
            }
        }
    }
    
    
    //-------------------------------------------------------------------------------------------
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/GameModeBase.h"
    
    #include "MyGameModeBase.generated.h"
    
    UCLASS()
    class VIVOXEXAMPLE_API AMyGameModeBase : public AGameModeBase
    {
        GENERATED_BODY()
    
    public:
        AMyGameModeBase();
    
        virtual void PostLogin(APlayerController* NewPlayer) override;
    
    private:
        FString m_VivoxServerGuid;
    };
    
    // -------------------------------------------- CPP
    #include "MyGameModeBase.h"
    #include "MyPlayerController.h"
    
    AMyGameModeBase::AMyGameModeBase()
    {
        m_VivoxServerGuid = FGuid::NewGuid().ToString(EGuidFormats::DigitsWithHyphens);
    }
    
    void AMyGameModeBase::PostLogin(APlayerController* NewPlayer)
    {
        Super::PostLogin(NewPlayer);
    
        if (AMyPlayerController* const ConnectingPlayerController = Cast<AMyPlayerController>(NewPlayer))
        {
            // TODO: Here you should get the PlayerState or whatever to get the players team - in Shifted we used an enum to determine teams (which is a uint8)
            ConnectingPlayerController->ClientJoinVoice(1, m_VivoxServerGuid);
        }
    }
    
  6. Should be good and working. If it isn't then feel free to reach out via Discord (trdwll#2006) or email ([email protected]com).

 

Last notes

So in the GameMode, I'm generating a guid for server identification. You could replace this with the actual session id (if using the session system in UE4) or you could even set it to the SteamID of the server (if using Steam) etc. The possibilities here are endless. You do however want a unique id for it so all players even in different servers don't join the same channel. 😁

This probably isn't the best or even the only way to implement Vivox, but I can say it does work. This is very similar to the implementation I did for Shifted and it's also mainly from the example project that Vivox made.

I also didn't implement push to talk here, but it's 100% doable. I believe the example project from Vivox has PTT.

 

 

I originally was going to post this over Summer 2020, but I never finished the post. So sorry for the delay, but it's finally here. 😀

 

until next time