メインコンテンツまでスキップ

Integrating Unreal voice chat into the game client

Last updated on August 9, 2023

Overview

This guide will walk you through the steps in integrating the Unreal Engine default implementation for Voice Chat into your game as push-to-talk voice chat using AccelByte OnlineSubsystem.

Goals

  • Modify AccelByte OnlineSubsystem (OSS) to include Unreal’s default FOnlineVoiceImpl
  • Enable push-to-talk voice chat for players

Prerequisites

Before you begin this guide, you should have the following:

  • You have knowledge of the Unreal Engine, including use of the OnlineSubsystem (OSS)
  • You have installed the AccelByte SDK and OnlineSubsystem plugins
  • You are using Unreal Engine 4.27.2 or above

Required Config Changes

To support voice chat, the following changes need to be made to the DefaultEngine.ini.

[OnlineSubsystem]
bHasVoiceEnabled=true
[Voice]
bEnabled=true
[/Script/Engine.GameSession]
bRequiresPushToTalk=false

Modifying the Accelbyte OSS Plugin

In order to enable push-to-talk voice chat using our OSS plugin, you will need to modify FOnlineSubsystemAccelByte so that FOnlineVoiceImpl will be initialized, though it is important to note that our plugin must fully initialize before you call initialization for FOnlineVoiceImpl. The best place to make that call is in :GetVoiceInterface.

Include the voice iterface as part of FOnlineSubsystemAccelByte:

FOnlineVoiceImplPtr VoiceInterface;
mutable bool bVoiceInterfaceInitialized = false;

bool FOnlineSubsystemAccelByte::Init()
{
...
VoiceInterface = MakeShared<FOnlineVoiceImpl, ESPMode::ThreadSafe>( this );
...
}

Initialize the voice interface when GetVoiceInterface is first called:

IOnlineVoicePtr FOnlineSubsystemAccelByte::GetVoiceInterface() const
{
if( !bVoiceInterfaceInitialized )
{
VoiceInterface->Init();
bVoiceInterfaceInitialized = true;
}
return VoiceInterface;
}

Include the voice interface Tick funciton:

bool FOnlineSubsystemAccelByte::Tick(float DeltaTime) 
{
...
if( bVoiceInterfaceInitialized && VoiceInterface.IsValid() )
{
VoiceInterface->Tick(DeltaTime);
}
...
}

Registering Local and Remote Talkers

Once the you have modified FOnlineSubsystemAccelByte to initialize the voice interface, you can include local and remote talker registration in the Session class as part of the RegiseterPlayer method. This will simply the process of adding players to voice chat, providing a seemless experience when they are join a game session or party, as parties are a type of session.

bool FOnlineSessionV2AccelByte::RegisterPlayers(FName SessionName, const TArray<TSharedRef<const FUniqueNetId>>& Players, bool bWasInvited /*= false*/)
{
...
for (const TSharedRef<const FUniqueNetId>& PlayerToAdd : Players)
{
...
if (FoundPlayerIndex == INDEX_NONE)
{
...
const EAccelByteV2SessionType SessionType = GetSessionTypeFromSettings( Session->SessionSettings );
if( SessionType == EAccelByteV2SessionType::GameSession && !IsRunningDedicatedServer())
{
if( AccelByteSubsystem->IsLocalPlayer( PlayerToAdd.Get() ) )
{
AccelByteSubsystem->GetVoiceInterface()->RegisterLocalTalker( 0 );
}
else
{
AccelByteSubsystem->GetVoiceInterface()->RegisterRemoteTalker( PlayerToAdd.Get() );
}
}
...
}
...
}
}

Unregistering Local and Remote Talkers

To unregister talkers, you will need to include UnregisterLocalTalkers and RemoveAllRemoteTalkers as part of the DestroySession method in the Session class. This will end the connection between the local player and the remote players.

bool FOnlineSessionV2AccelByte::DestroySession(FName SessionName, const FOnDestroySessionCompleteDelegate& CompletionDelegate /*= FOnDestroySessionCompleteDelegate()*/)
{
...
AccelByteSubsystem->GetVoiceInterface()->UnregisterLocalTalkers();
AccelByteSubsystem->GetVoiceInterface()->RemoveAllRemoteTalkers();
...
}

Assigning a Button for Push-to-Talk

To enable push-to-talk, it is necessary to assing a button that players can use to turn on/off the microphone so they can be heard by others. This setup will vary from game to game, but below is an example of how to setup the slash ('/') key to turn on voice chat.

[/Script/Engine.InputSettings]
...
+ActionMappings=(ActionName="ToggleSpeak",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Slash)
void AGamePlayerController::BeginPlay()
{
...
#if !UE_SERVER
InputComponent->BindAction("ToggleSpeak", EInputEvent::IE_Pressed, this, &APlayerController::StartTalking);
InputComponent->BindAction("ToggleSpeak", EInputEvent::IE_Released, this, &APlayerController::StopTalking);
#endif
}

Known Issues

  1. There are some differences between a Windows server (Local DS) and a Linux server (Armada) that can lead to different behavior, such as a Linux server being unalbe to read push-to-talk settings, it can only use settings that are enabled by default. This means the server will always send a command to disable network voice, requiring the game to implement a process to enable network voice so plaeyrs can talk freely wihtout pressing a Key.

  2. While this has been tested and works for game sessions that run on dedicated servers, peer-to-peer is currnetly untested.

Troubleshooting

In this section, you can find common errors and issues that may occur when using the service, along with recommendations on how to resolve them.

Missing Push-to-Talk Audio when Testing Two Clients Locally

When running two clients locally using push-to-talk, you may experience an isue hearing one of the clients voice chat. This is because Unreal, by default, mutes the audio of an instance when it's window loses focus. To resolve this for testing on the same machine, you can update the unfocused audio modifier in the DefaultEngine.ini to 1.0 instead of 0.0.

[Audio]
UnfocusedVolumeMultiplier=1.0