From eacf1a870d2c0997efd79f0663d7e5ae5a1633ce Mon Sep 17 00:00:00 2001
From: jehret <ehret@vr.rwth-aachen.de>
Date: Fri, 30 Jun 2023 14:05:56 +0200
Subject: [PATCH] cluster sync audio signal play state

---
 .../SignalSources/VAAudiofileSignalSource.cpp | 43 ++++++++++++++-----
 .../SignalSources/VAAudiofileSignalSource.h   | 26 +++++++----
 2 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp b/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp
index 5ed4c1e..1fe8e09 100644
--- a/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp
+++ b/Source/VAPlugin/Private/SignalSources/VAAudiofileSignalSource.cpp
@@ -13,6 +13,7 @@
 
 void UVAAudiofileSignalSource::Initialize()
 {
+	StorePlayStateInternallyEvent.Attach(this);
 	if (bInitialized)
 	{
 		FVAUtils::LogStuff("[UVAAudiofileSignalSource::Initialize()]: Signal source is already initialized, aborting...", false);
@@ -27,6 +28,11 @@ void UVAAudiofileSignalSource::Initialize()
 	bInitialized = true;
 }
 
+UVAAudiofileSignalSource::~UVAAudiofileSignalSource()
+{
+	StorePlayStateInternallyEvent.Detach();
+}
+
 // ****************************************************************** // 
 // ******* Bluepring Functions ************************************** //
 // ****************************************************************** //
@@ -111,6 +117,7 @@ bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN)
 		return true;
 	}
 
+	bLoop = bLoopN;
 	
 	if (!UVirtualRealityUtilities::IsMaster())
 	{
@@ -122,7 +129,6 @@ bool UVAAudiofileSignalSource::SetLoop(const bool bLoopN)
 		return true;
 	}
 
-	bLoop = bLoopN;
 	return FVAPlugin::SetSignalSourceBufferLooping(ID, bLoop);
 }
 
@@ -137,15 +143,16 @@ bool UVAAudiofileSignalSource::SetPlayBackPosition(const float Time)
 
 bool UVAAudiofileSignalSource::SetPlayAction(const int Action)
 {
+	InterallyStoredPlayAction = Action;
+	StorePlayStateInternallyEvent.Send(Action); //also send this to all slaves, so potentially still pending send numbers from GetPlayAction are overwritten
+
+	FVAUtils::LogStuff("set play action to " + FString::FromInt(InterallyStoredPlayAction) + "   (and stored internally)");
+
 	if (!UVirtualRealityUtilities::IsMaster())
 	{
 		return false;
 	}
 
-	if (int(GetPlayAction()) == Action)
-	{
-		return true;
-	}
 	return FVAPlugin::SetSignalSourceBufferPlayAction(ID, EPlayAction::Type(Action));
 }
 
@@ -165,18 +172,28 @@ bool UVAAudiofileSignalSource::GetLoop() const
 	return bLoop;
 }
 
-EPlayAction::Type UVAAudiofileSignalSource::GetPlayActionEnum() const
+EPlayAction::Type UVAAudiofileSignalSource::GetPlayActionEnum()
 {
 	return EPlayAction::Type(GetPlayAction());
 }
 
-int UVAAudiofileSignalSource::GetPlayAction() const
+int UVAAudiofileSignalSource::GetPlayAction()
 {
-	if (!UVirtualRealityUtilities::IsMaster())
+	//we return the internally stored action in case this is in cluster and not the master
+	//but also update the internally stored data by the one which the master can get from the VAServer
+	//However, using cluster events to sync, so new data might only be available next frame!
+	if (UVirtualRealityUtilities::IsMaster())
 	{
-		return -1;
+		// in case of not being in cluster mode this directly calls StorePlayStateInternally() updating InterallyStoredPlayAction directly
+		// otherwise (in cluster mode) this emits acluster event, so the internal data will be updated before next Tick
+		int VAServerPlayAction = FVAPlugin::GetSignalSourceBufferPlayAction(ID);
+		StorePlayStateInternallyEvent.Send(VAServerPlayAction);
+		FVAUtils::LogStuff("send " + FString::FromInt(VAServerPlayAction)+ "   as cluster event");
 	}
-	return FVAPlugin::GetSignalSourceBufferPlayAction(ID);
+
+	FVAUtils::LogStuff("returned stored play action " + FString::FromInt(InterallyStoredPlayAction));
+
+	return InterallyStoredPlayAction;
 }
 
 bool UVAAudiofileSignalSource::CopySignalSourceSettings(const std::string& OtherID)
@@ -202,3 +219,9 @@ bool UVAAudiofileSignalSource::CopySignalSourceSettings(const std::string& Other
 	}
 	return FVAPlugin::SetSignalSourceBufferPlayAction(OtherID, EPlayAction::Type(PlayAction));
 }
+
+void UVAAudiofileSignalSource::StorePlayStateInternally(int PlayAction)
+{
+	FVAUtils::LogStuff("set " + FString::FromInt(PlayAction) + "   from cluster event");
+	InterallyStoredPlayAction = PlayAction;
+}
diff --git a/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h b/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h
index a7639b5..ecc8179 100644
--- a/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h
+++ b/Source/VAPlugin/Public/SignalSources/VAAudiofileSignalSource.h
@@ -5,10 +5,13 @@
 #include "VAEnums.h"
 #include "../../Private/SignalSources/VAAudiofileManager.h"
 
+
+#include "Events/DisplayClusterEventWrapper.h"
 #include <string>
 
 #include "CoreMinimal.h"
 #include "SignalSources/VAAbstractSignalSource.h"
+
 #include "VAAudiofileSignalSource.generated.h"
 
 
@@ -22,6 +25,7 @@ class VAPLUGIN_API UVAAudiofileSignalSource : public UVAAbstractSignalSource
 	
 public:
 	UVAAudiofileSignalSource() = default;
+	~UVAAudiofileSignalSource();
 
 	// Creates the signal source in VA and sets the ID accordingly
 	void Initialize() override;
@@ -68,10 +72,13 @@ public:
 	FString GetFilename() const;
 	UFUNCTION(BlueprintCallable)
 	bool GetLoop() const;
-	UFUNCTION(BlueprintCallable)
-	EPlayAction::Type GetPlayActionEnum() const;
 
-	int GetPlayAction() const;
+	//GetPlayActionEnum() might be one tick behind in cluster mode, since the current play action is only synced between master and slaves after this is called
+	//so make sue to, e.g., call this every frame or at least multiple times (if you, e.g., want to observe a change from play to pause)
+	UFUNCTION(BlueprintCallable) 
+	EPlayAction::Type GetPlayActionEnum();
+
+	int GetPlayAction();
 
 	// *** Events/Delegates *** //
 
@@ -84,11 +91,6 @@ protected:
 	// @return True on success
 	bool CopySignalSourceSettings(const std::string& ID);
 
-private:
-	FChangedAudiofileEvent AudiofileChangedEvent;
-
-
-protected:
 	// Action of the sound source at the first tick
 	UPROPERTY(EditAnywhere, meta = (DisplayName = "Starting State", Category = "Audio file"))
 		TEnumAsByte<EPlayAction::Type> StartingPlayAction = EPlayAction::Type::Stop;
@@ -108,5 +110,13 @@ protected:
 		bool bLoop = false;
 
 private:
+
+	void StorePlayStateInternally(int PlayAction);
+	DECLARE_DISPLAY_CLUSTER_EVENT(UVAAudiofileSignalSource, StorePlayStateInternally);
+	int InterallyStoredPlayAction = -1;
+
+
+	FChangedAudiofileEvent AudiofileChangedEvent;
+
 	FVAAudiofileManager AudiofileManager;
 };
-- 
GitLab