From c8ebb6b93607b7f14afabd407a0df5da6c0e17b6 Mon Sep 17 00:00:00 2001
From: Nicholas Nakano <nicksnak01@gmail.com>
Date: Wed, 24 Aug 2022 13:07:20 -0700
Subject: [PATCH] Added Voice Chat code to Gamemode and Controller

---
 .../Private/ARNOPlayerController.cpp          | 46 +++++++++++++++
 .../arnocMain/Public/ARNOPlayerController.h   | 15 ++++-
 Source/arnocMain/arnocMainGameModeBase.cpp    | 56 +++++++++++++++++++
 Source/arnocMain/arnocMainGameModeBase.h      |  9 +++
 4 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/Source/arnocMain/Private/ARNOPlayerController.cpp b/Source/arnocMain/Private/ARNOPlayerController.cpp
index 7c145d7..e0b32dc 100644
--- a/Source/arnocMain/Private/ARNOPlayerController.cpp
+++ b/Source/arnocMain/Private/ARNOPlayerController.cpp
@@ -2,4 +2,50 @@
 
 
 #include "ARNOPlayerController.h"
+#include <ArnoEOSSubsystem.h>
 
+void AARNOPlayerController::OnLoginComplete(const FString& PlayerName, const FVoiceChatResult& Result)
+{
+    if (Result.IsSuccess())
+    {
+        FString DeviceName = VoiceChatUser->GetDefaultInputDeviceInfo().DisplayName;
+        UE_LOG(LogTemp, Display, TEXT("VOIP Initialized: Using %s as input device."), *DeviceName);
+    }
+}
+
+void AARNOPlayerController::DoLogin()
+{
+    UArnoEOSSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UArnoEOSSubsystem>();
+    VoiceChatUser = Subsystem->VoiceChatInitialize();
+}
+
+void AARNOPlayerController::BeginDestroy()
+{
+    UArnoEOSSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UArnoEOSSubsystem>();
+    if (Subsystem != nullptr)
+    {
+        Subsystem->VoiceChatDeinitialize(VoiceChatUser);
+    }
+	Super::BeginDestroy();
+}
+
+void AARNOPlayerController::JoinVoiceChannel_Implementation(const FString& InChannelName,
+                                                            const FString& InChannelCredentials)
+{
+    if (VoiceChatUser == nullptr)
+    {
+        return;
+    }
+
+    VoiceChatUser->JoinChannel(
+        InChannelName,
+        InChannelCredentials,
+        EVoiceChatChannelType::Positional,
+        FOnVoiceChatChannelJoinCompleteDelegate::CreateLambda([](const FString& ChannelName, const FVoiceChatResult& Result)
+            {
+                if (Result.IsSuccess())
+                {
+                    UE_LOG(LogTemp, Display, TEXT("User has joined Voice Chat."));
+                }
+            }));
+}
diff --git a/Source/arnocMain/Public/ARNOPlayerController.h b/Source/arnocMain/Public/ARNOPlayerController.h
index f20356c..b51e3d6 100644
--- a/Source/arnocMain/Public/ARNOPlayerController.h
+++ b/Source/arnocMain/Public/ARNOPlayerController.h
@@ -4,6 +4,7 @@
 
 #include "CoreMinimal.h"
 #include "GameFramework/PlayerController.h"
+#include "VoiceChat.h"
 #include "ARNOPlayerController.generated.h"
 
 /**
@@ -13,5 +14,17 @@ UCLASS()
 class ARNOCMAIN_API AARNOPlayerController : public APlayerController
 {
 	GENERATED_BODY()
-	
+
+	IVoiceChatUser* VoiceChatUser;
+
+	void OnLoginComplete(const FString& PlayerName, const FVoiceChatResult& Result);
+
+	UFUNCTION(BluePrintCallable)
+	void DoLogin();
+
+public:
+	UFUNCTION(Client, Reliable)
+	void JoinVoiceChannel(const FString& InChannelName, const FString& InChannelCredentials);
+
+	virtual void BeginDestroy() override;
 };
diff --git a/Source/arnocMain/arnocMainGameModeBase.cpp b/Source/arnocMain/arnocMainGameModeBase.cpp
index d6b4459..5867ee9 100644
--- a/Source/arnocMain/arnocMainGameModeBase.cpp
+++ b/Source/arnocMain/arnocMainGameModeBase.cpp
@@ -51,6 +51,45 @@ void AarnocMainGameModeBase::PostLogin(APlayerController* NewPlayer)
 	}
 
 	Super::PostLogin(NewPlayer);
+
+	// Voice Chat Channel Initialization:
+	if (NewPlayer->IsLocalPlayerController())
+	{
+		return;
+	}
+
+	AARNOPlayerController* CustomPC = Cast<AARNOPlayerController>(NewPlayer);
+	if (!IsValid(CustomPC))
+	{
+		// Not the correct type of player controller.
+		return;
+	}
+	UNetConnection* IncomingNetConnection = Cast<UNetConnection>(CustomPC->Player);
+	if (!IsValid(IncomingNetConnection) || !IncomingNetConnection->PlayerId.IsValid())
+	{
+		// Not a networked player controller, or there's no player ID.
+		return;
+	}
+
+	TSharedPtr<IOnlineIdentity, ESPMode::ThreadSafe> Identity = Subsystem->GetIdentityInterface();
+	TSharedPtr<IOnlineVoiceAdmin, ESPMode::ThreadSafe> VoiceAdmin = Online::GetVoiceAdminInterface(Subsystem);
+
+	// For the channel name you could use the current session ID. It's up to you
+	// to choose an appropriate value based on how you want to group players in
+	// voice chat.
+	FString ChannelName = Session->GetNamedSession("MyLocalSessionName")->GetSessionIdStr();
+
+	TArray<TSharedRef<const FUniqueNetId>> TargetUserIds;
+	TargetUserIds.Add(IncomingNetConnection->PlayerId.GetUniqueNetId().ToSharedRef());
+	VoiceAdmin->CreateChannelCredentials(
+		*Identity->GetUniquePlayerId(0), // This will get the "dedicated server" ID.
+		ChannelName,
+		TargetUserIds,
+		FOnVoiceAdminCreateChannelCredentialsComplete::CreateUObject(
+			this,
+			&AarnocMainGameModeBase::IssuedCredentialsForPlayer,
+			ChannelName,
+			CustomPC));
 }
 
 AarnocMainGameModeBase::AarnocMainGameModeBase()
@@ -100,3 +139,20 @@ void AarnocMainGameModeBase::RegisterExistingPlayers()
 
 	bExistingPlayersRegistered = true;
 }
+
+void AarnocMainGameModeBase::IssuedCredentialsForPlayer(const FOnlineError& Result, const FUniqueNetId& LocalUserId,
+	const TArray<FVoiceAdminChannelCredentials>& Credentials, FString InChannelName, AARNOPlayerController* NewPlayer)
+{
+	if (!Result.WasSuccessful())
+	{
+		return;
+	}
+
+	// We're making one CreateChannelCredentials call per player, so we can assume that the only entry in the
+	// results is for the player this callback is associated with. If you were requesting credentials for multiple
+	// target players, you'd have to iterate through Credentials to find the matching "TargetUserId" field.
+	if (IsValid(NewPlayer))
+	{
+		NewPlayer->JoinVoiceChannel(InChannelName, Credentials[0].ChannelCredentials);
+	}
+}
diff --git a/Source/arnocMain/arnocMainGameModeBase.h b/Source/arnocMain/arnocMainGameModeBase.h
index b5d3cd3..153b26b 100644
--- a/Source/arnocMain/arnocMainGameModeBase.h
+++ b/Source/arnocMain/arnocMainGameModeBase.h
@@ -3,9 +3,11 @@
 #pragma once
 
 #include "CoreMinimal.h"
+#include "ARNOPlayerController.h"
 #include "GameFramework/GameModeBase.h"
 #include "OnlineSubsystem.h"
 #include "OnlineSubsystemUtils.h"
+#include "RedpointEOSInterfaces/Private/Interfaces/OnlineVoiceAdminInterface.h"
 #include "arnocMainGameModeBase.generated.h"
 
 /**
@@ -26,4 +28,11 @@ public:
 
 private:
 	bool bExistingPlayersRegistered;
+
+	void IssuedCredentialsForPlayer(
+		const FOnlineError& Result,
+		const FUniqueNetId& LocalUserId,
+		const TArray<FVoiceAdminChannelCredentials>& Credentials,
+		FString InChannelName,
+		AARNOPlayerController* NewPlayer);
 };
-- 
GitLab